Search code examples
functional-programmingsml

Standard ML: Truncating String


I know ML has a bunch of string methods (substring, etc) that would make this easier but I want to get more comfortable with the language, so I'm implementing some myself.

I'm trying to truncate a string, i.e. cut off the string after a certain number of characters. I think I'm very close but am getting a syntax error when I do

val x::xs = explode(myString);

Here's the full code:

fun getAllButLast([x]) = nil
    | getAllButLast(x::xs) = x::getAllButLast(xs);

fun truncate(myString, 0) = ""
    | truncate(myString, limit:int) =
    let
        val x::xs = explode(myString);
    in
        x::truncate(implode(getAllButLast(xs)), limit - 1)
    end;

Thoughts on why the compiler doesn't like this?

val x::xs = explode(myString);

Thanks for the help, bclayman

Edit to include error:

Ullman.sml:82.5-82.55 Error: operator and operand don't agree [tycon mismatch]
  operator domain: char * char list
  operand:         char * string
  in expression:
    x :: truncate (implode (getAllButLast <exp>),limit - 1)

uncaught exception Error
  raised at: ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
             ../compiler/TopLevel/interact/evalloop.sml:44.55
             ../compiler/TopLevel/interact/evalloop.sml:292.17-292.20

Solution

  • As the error message shows, it is complaining about a different line. And it is complaining because the right operand of the :: operator in that line (the result of the recursive call to truncate) is a string, not a list. You probably want to use ^ instead, which denotes string concatenation.

    Hint: There are other issues with your code. At least it is extremely inefficient. You should generally avoid implode/explode, but if you must use them, you should at least only call each of them once for the whole string, and not once for every character in the recursion.