Checking elements of a list in SML

4.7k views Asked by At

Hi I am relatively new to ML/SML and I am trying to write function that takes as input 2 lists. The one list contains 4 random strings ["duck","goose","swan","gull"] and the second takes another 4 strings ["duck","swan","goose","pigeon"].

What I would like to do i check each element in the first list against each element the other. If the strings are in the same position and are equal output a 'yes'. If the elements are not in the same position but are in the list then output 'maybe', and if the element isn't in the second list output 'no'.

So given the 2 examples above it would output ["yes","maybe","maybe","no"].

This is what I have done so far, but I can't figure out how to keep recursively calling the main function, checkEqual, to iterate over the entire first list.

 fun buildStringList nil nil = nil
|buildStringList lst appList = 
    lst @ appList   
in
fun checkEqual nil nil = nil
| checkEqual code guess =
    if hd code = hd guess then
        buildStringList ([])(["yes"])
    else if hd code = hd(tl guess) then
        buildStringList ([])(["maybe"])
    else if hd code = hd(tl(tl guess)) then
        buildStringList ([])(["maybe"])
    else if hd code = hd(tl(tl(tl guess))) then
        buildStringList ([])(["maybe"])
    else 
        buildStringList ([])(["no"])        
end;

Any help would be greatly appreciated.

1

There are 1 answers

1
ben rudgers On BEST ANSWER

There are two code paths, comparing items by index [the "yes" condition] and then comparing them without regard to index [the "maybe" path]. Using recursion and a helper function [or two] allows both code paths to be followed:

val ls1 = ["duck", "goose", "swan", "gull"]
val ls2 = ["duck", "swan", "goose", "pigeon"]

fun checker (list1,list2) =
    (* Zipping the two lists together  creates
       a list of pairs that can be searched
       for "yes" values as the first part of the aux function. 
       It might be worth checking to see if
       ListPair.zipEq is more suited to the
       needs of a particular appliation. *)        
    let val zipped =  ListPair.zip(list1, list2)

    (*  find_in_list is called if there is
        no "yes" match. It recurses down
        list2 with the string from list1
        which did not return "yes". *)
    fun find_in_list (x, xs) =
        case xs
         of [] => "no"
         | x'::xs' => 
           if x' = x
           then "maybe"
           else find_in_list (x, xs')
    (*  This function could be the main body
        of checker, but instead it trampolines.
        First it checks for "yes". Either appends
        "yes" onto a recursive call to itself or
        otherwise appends a call to find_in_list
        onto a recursive call to itself. 
        The type checker wants an explicit type
        for lop because the record is being accessed
        with #1 and #2 *)
    fun aux (lop : (string * string) list) =
        case lop
         of [] => []
         | x'::xs' =>
           if #1 (hd lop) = #2 (hd lop)
           then "yes"::aux (tl lop)
           else (find_in_list (#1 (hd lop), list2))::(aux (tl lop))
    in aux(zipped) end

checker (ls1,ls2)  (* returns ["yes", "maybe", "maybe", "no"] *)