Search code examples
typesfunctional-programmingsmlsmlnjml

ML list typing when converting char list to int list


I've been having an issue with converting a character list to an int list. My goal is to basically take a number such as 325 and have it return a list of [3,2,5]. What I've done so far is take the number and then convert it to a string, which then gets exploded to a char array. I then want to convert each char to a respective int. When I map my char list into fn c => Char.ord(c) the char list becomes an ?.int list, which prevents me from doing operations(+,-) on it. I'm new to ML and don't have a strong grasp of its type system but it seems odd to me.

Here's the code:

open IntInf;

fun fact_helper (0, r : int) = r
  | fact_helper (n : int, r : int) = fact_helper (n-1, n*r);

fun factorial n:int = fact_helper (n, 1);

fun num_to_digits n =  
    let val digits_as_chars = explode (IntInf.toString n);
    in map (fn c => (Char.ord c)) digits_as_chars
    end;

Ideally I'd like to be able to do fn c => (Char.ord c) - 48 in my mapping function to get the true digit value. I've done something similar before and it worked then but not now and I'm unsure why I'm getting the ?.int list type. Original problem can be found as Project Euler problem 20.


Solution

  • The problem is that you did open IntInf, so that type int and operators + and friends now refer to the IntInf module. The ordinary int type got shadowed by IntInf.int and thus is printed as ?.int (SML/NJ uses the pseudo syntax ?.x to refer to names from inaccessible scopes). Char.ord returns the ordinary int type.

    So nothing is necessarily wrong with your code, but the open can have a confusing effect. You should generally avoid using open in the toplevel scope.

    If you really want your num_to_digits function to compute with infinite integers then you'll have to wrap a call to IntInf.fromInt (or just fromInt, since IntInf is opened) around Char.ord c.