Search code examples
smlsmlnj

Where does "#" come from in SML?


I'm trying to make the function which takes string and transforms it to boolean expression. For example:for input ((x10+~1)*x132) it should give times(plus(var 10,compl 1),var 132), but it gives times(plus(var #,compl #),var 132). Where do hashtags come from??

datatype boolexp = zero
                 | one 
                 | plus of boolexp * boolexp 
                 | times of boolexp * boolexp
                 | var of int
                 | compl of boolexp

exception InvalidInput

(* takes the first n elements *)
fun take (_, 0) = nil
  | take (nil, _) = raise InvalidInput
  | take (h::t, n) = if n < 0
                     then raise InvalidInput
                     else h::take(t, n-1)

(* drops the frist n elements *)
fun drop (xs, 0) = xs
  | drop (nil, _) = raise InvalidInput
  | drop (h::t,n) = if n < 0
                    then raise InvalidInput
                    else drop (t, n-1)

(* converts string to integer *)
fun charlist_to_int (nil) = raise InvalidInput 
  | charlist_to_int (xs) =
    let fun helper_int_rev (nil) = 0
          | helper_int_rev (h::t) = if h >= #"0" andalso h <= #"9"
                                    then helper_int_rev t * 10 + (ord h - ord #"0")
                                    else raise InvalidInput
    in helper_int_rev (rev xs) end;

(* finds the operator and its position *)
fun searchfor_oper (nil,_,_) = raise InvalidInput
  | searchfor_oper (#"("::t, np, pos) = searchfor_oper (t, np+1, pos+1)
  | searchfor_oper (#")"::t, np, pos) = searchfor_oper(t, np-1, pos+1)
  | searchfor_oper (#"+"::t, 0, pos) = (pos, #"+")
  | searchfor_oper (#"*"::t, 0, pos) = (pos, #"*")
  | searchfor_oper (h::t, np, pos) = searchfor_oper (t, np, pos+1)

fun beparse_helper (nil) = raise InvalidInput
  | beparse_helper (h::t) =
    if h = #"x" then if hd(t)= #"0" then raise InvalidInput
    else var (charlist_to_int (t))
    else if h = #"0" then if t = nil then zero else raise InvalidInput
    else if h = #"1" then if t = nil then one else raise InvalidInput
    else if h = #"~" then compl(beparse_helper(t))
    else if h = #"(" then
    let
        val lst = if hd (rev t)= #")" then take(t, length(t)-1) else raise InvalidInput
        val (pos, oper) = searchfor_oper (lst, 0, 1)
    in
        if oper = (#"+")
        then plus(beparse_helper(take(lst,pos-1)), beparse_helper(drop(lst,pos)))
        else if oper = (#"*")
             then times(beparse_helper(take(lst,pos-1)),beparse_helper(drop(lst,pos)))
             else raise InvalidInput 
    end
    else raise InvalidInput;

fun beparse(s) = beparse_helper(explode(s));

(*TESTING*)
beparse ("((x10+~1)*x132)");

Solution

  • I don't think that it is SML per se so much as SML/NJ default REPL output. In the grand scheme of things the REPL is for development/debugging -- not the environment for the finished program to run it. Recursive data structures such as trees can give quickly give rise to values which are too big to conveniently print. The REPL truncates the output in a couple of ways. For lists it will print around a dozen elements and then use .... For things like trees it will print down a few levels and then use a # to indicate that you have reached the level where the truncation happens. If you find this inconvenient you can do one of two things:

    1) The logical printing depth in SML/NJ can be altered by evaluating Control.Print.printDepth := 20; (or however much you want) in the REPL

    2) Perhaps a little more principled but more work -- write a custom pretty-printer (say pprint) for your values and evaluate e.g. pprint v; in the REPL rather than just v;