Search code examples
smlsmlnj

How can I make a function that takes two lists as args and returns true if the first list exists in the second?


I have to write this in sml/nj I made a try and this is what I did:

I want the all function to return a positive number when I run the function but for example when I give [1,2,3] [1,1,2,3,1,2,3,1] it returns nonexhaustive match failure. What is wrong with the function and what can I do to see if the elements of the first list exist in the second?

fun elem num [] = false
  | elem num (x::xs) = if num = x then true else elem num xs

fun all [] [] =
  let
    fun qwe [] [] acc = acc
      | qwe (x::xs) (z::zs) acc = if elem x (z::zs) then qwe xs (z::zs) (1+acc) else qwe xs (z::zs) acc
  in
    qwe [] [] 0
  end

Solution

  • In your definition of all, you seem to be slipping into thinking of [] as being a generic list rather than an empty list.

    The only pattern that actually appears in your definition of all is [] [] (two empty lists). That is most emphatically a case of nonexhaustive matching.

    Since the helper function qwe does the actual work, there really isn't any point in having pattern-matching on all itself. The overall form of all could be:

    fun all xs ys =
      let
        fun qwe = (*insert definition*)
      in
        qwe xs ys 0
      end;
    

    (using zs rather than ys here looks a bit awkward)

    The definition of que should have 2-4 patterns. A 4-pattern definition (required for some functions which operate on two lists would be):

    fun qwe [] [] acc = (*insert def*)
      | qwe [] (y::ys) acc = (*insert def*)
      | qwe (x::xs) [] acc = (*insert def*)
      | qwe (x::xs) (y::ys) acc = (*insert def*)
    

    This last gives 4 cases, one for each Boolean combination of the first list and the second list being empty. Sometimes you don't need to write separate code for each of those. For example,

    fun qwe [] [] acc = (*insert def*)
      | qwe [] ys acc = (*insert def*)
      | qwe (x::xs) ys acc = (*insert def*)
    

    combines the 3rd and 4th case into a single case.

    If you look at your actual definition of elem, you realize that it handles the case of empty ys nicely, so in your definition of qwe, you can really just have two patterns based on what xs is doing:

    fun qwe [] ys acc = (*insert def*)
      | qwe (x::xs) ys acc = (*insert def*) 
    

    Since ys can match both empty and nonempty lists, the above template is exhaustive.

    With the appropriate definitions (which you essentially already have) for the above two cases of que, your function all will work:

    - all [1,2,3] [1,1,2,3,1,2,3,1];
    val it = 3 : int