Search code examples
functional-programmingsmlml

Implement last using ML


I'm trying to implement last in ML. last can return the last element of a list.

For example, L=[1, 2, 3, 4], last(L) = 4. Here is my implementation.

fun last [] = last((h::nil)) = h | last((h::tail)) = last(tail);

It give me "unbound variable or constructor: h". In my understanding, h is a variable declared by me, representing the head of the list, why error would occur on variable h?


Solution

  • You definition can be laid out as

    fun last [] = last((h::nil)) = h 
    | last((h::tail)) = last(tail);
    

    SML interprets the first clause as an attempt to assign to last [] the Boolean value which is the result of the comparison last((h::nil)) = h. Since the pattern that you are matching in that clause is [] and [] doesn't involve h, the h in the comparison last((h::nil)) = h is unbound, hence the error. In any event such a comparison would make very little sense and is clearly not your intention.

    Note that last [] can't be sensibly defined. You alternatives is to either simply ignore it or to address it by raising an error (either Empty or a custom error). The real basis clause of the function last is that of a 1-element list. You seem to know how to handle it. Your code actually works when you stop trying to use your first clause to simultaneously give a value to both last [] and last (h::nil) and instead just do the latter:

    fun last (h::nil) = h 
    | last (h::tail) = last tail;
    

    Here I removed 3 pairs of superfluous parentheses around h::nil, h::tail, and tail. In SML function invocation requires no parentheses. You only need parentheses when you need to insure proper grouping. Note that the first pattern can also be written more succintly as [h].

    You get a nonexahaustive match warning since you haven't given a definition for last []. You could just ignore the warning (since it is rather common with functions only defined for nonempty lists), or write it as

    fun last [] = raise Empty
    |   last (h::nil) = h 
    |   last (h::tail) = last tail;