Search code examples
smlsmlnj

delete white spaces from char list - sml


I am trying to delete the empty entries from a char list in sml.

This is my function but when I try to call it, it doesn't work and brings a fatal error.

fun no_spaces([]) = raise Empty
  | no_spaces(e::f) = if(e = #" ") then no_spaces(f) else e::no_spaces(f);

no_spaces [#"a",#"a",#" ",#"d",#" "];

What am I doing wrong?

Thank you

P.S Or if this is not possible, then how can I delete empty spaces from a string?


Solution

  • I suspect that by raise Empty you meant to return the empty list rather than trigger a runtime error. You have indicated in the comments that you have fixed that particular bug, but it can't hurt to say a bit more about when you should return nil and when you should raise empty.

    As a general rule of thumb, if you are defining a function which sends lists to lists and the output list is constructed by processing the elements of the input list one by one (e.g. return the list of even elements in an int list, which involves checking the parity of each element in turn) then your basis case should be something like fun f [] = [] because an empty input corresponds to nothing left to process, and if there is nothing left to process then there is nothing left to return.

    But -- if the goal of the function on lists is to return an element of the list (such as the first even entry) then it is natural to raise Empty:

    fun firstEven [] = raise Empty
    |   firstEven (x::xs) = if x mod 2 = 0 then x else firstEven xs; 
    

    Here raise Empty makes perfect: since [] doesn't contain any integer it doesn't contain a first even one to return. Thus, this is an error situation which (ideally) should be addressed with a handle somewhere in the calling function.

    An argument could be made that raise Empty should never be used since SML provides an alternative error handling method which uses the option type constructor. The function firstEven could be rewritten

    fun firstEven [] = NONE
    |   firstEven (x::xs) = if x mod 2 = 0 then SOME x else firstEven xs;
    

    in this case the calling function would pattern match on the returned value(using the two patterns NONE and SOME x) rather than providing an exception handler. Conceptually this second approach is cleaner and possibly even more efficient (it seems to be in F#, see this, I'm not sure about SML).

    See this for a discussion of the two error handling methods in SML.