SMLNJ function that returns as a pair a string at the beginning of a list

204 Views Asked by At

So im really confused as i am new to sml and I am having trouble with syntax of how i want to create my function.

the instructions are as follows...

numberPrefix: char list → string * char list

Write a function named numberPrefix that returns (as a pair) a string representing the digit characters at the beginning of the input list and the remaining characters after this prefix. You may use the Char.isDigit and String.implode functions in your implementation. For example,

  • numberPrefix [#"a", #"2", #"c", #" ", #"a"];

val it = ("", [#"a", #"2", #"c", #" ", #"a") : string * char list

  • numberPrefix [#"2", #"3", #" ", #"a"];

val it = ("23", [#" ", #"a"]) : string * char list

Here is my code so far...

fun numberPrefix(c:char list):string*char list =
case c of
[] => []
|(first::rest) => if isDigit first
                  then  first::numberPrefix(rest)
                  else  

;

I guess what i am trying to do is append first to a seperate list if it is indeed a digit, once i reach a member of the char list then i would like to return that list using String.implode, but I am banging my head on the idea of passing in a helper function or even just using the "let" expression. How can I essentially create a seperate list while also keeping track of where i am in the original list so that I can return the result in the proper format ?

1

There are 1 best solutions below

0
On

First of all, the function should produce a pair, not a list.
The base case should be ("", []), not [], and you can't pass the recursive result around "untouched".
(You can pretty much tell this from the types alone. Pay attention to types; they want to help you.)

If you bind the result of recursing in a let, you can access its parts separately and rearrange them.
A directly recursive take might look like this:

fun numberPrefix [] = ("", [])
  | numberPrefix (cs as (x::xs)) = 
        if Char.isDigit x
        then let val (number, rest) = numberPrefix xs 
             in
                 ((str x) ^ number, rest)
             end
        else ("", cs);

However, splitting a list in two based on a predicate – let's call it "splitOn", with the type ('a -> bool) -> 'a list -> 'a list * 'a list – is a reasonably useful operation, and if you had that function you would only need something like this:

fun numberPrefix xs = let val (nums, notnums) = splitOn Char.isDigit xs
                      in
                          (String.implode nums, notnums)
                      end;

(Splitting left as an exercise. I suspect that you have already implemented this splitting function, or its close relatives "takeWhile" and "dropWhile".)