0

I'm writing a function in sml which checks if an initial list is contained within any aspect of the second list. Here is what I have so far:

fun contains l1 [] = false 
    | contains l1 (hd::tl) = contains l1 tl 
    | contains l1 l2 = starts l1 l2;

EDIT: Here is my starts function (Checks if list l1 starts l2):

fun starts [] l2 = true 
    | starts l [] = false 
    | starts (h1::t1) (h2::t2) = if((h1=h2) andalso (starts t1 t2)) then true else false;

It however gives me the error:

stdIn:21.3-21.97 Error: match redundant

Can anyone help me figure out why?

Thanks

madcrazydrumma
  • 1,847
  • 3
  • 20
  • 38

1 Answers1

1

the reason for the error is because this line: contains l1 l2 = starts l1 l2; is no different from the previous line: contains l1 (hd::tl) = contains l1 tl

Both lines express an identical matching pattern. You can see this as you can write: contains l1 (l2 as (hd::tl)) = contains l1 tl This will confuse the interpreter as you are telling it that in the case of this pattern: contains l1 l2, do two different things, namely:

starts l1 l2; and

contains l1 tl

The way to get to your solution here is to eliminate the last line of contains as it is redundant.

In the second line your purpose is to now loop over the initial elements of the second list until you get to a point where the 'current element' of the second list matches the first element of the first list. If this is the case, then invoke start else continue looping.

Consider val first_list = [2,3,4] and val second_list = [1,2,2,2,2,3,4,5,6]

So contains in the second line will have to first loop over the elements of the second_list to see if the first elements match. If they match then invoke start. So you get following breakdown:

2=1? => false thus loop to second element

2=2? => true thus invoke start to see if we have a matching list from then onwards.

As start will return false the moment it checks 3=2? => false, you now have to continue looping in contains and repeat this procedure. It will have to loop until it reaches the final 2 in second_list. At this point the comparison will be like this:

2=2? => true thus invoke start to check to see if the consecutive elements match. start will now evaluate to true as follows:

3=3? => true

4=4? => true

5=5? => true --> At this point start will return true which should be the return value of contains as well. If start at any point returns false then you need to continue looping. Eventually you will pattern match first_list with [] which will be caught by your first line.

NOTE: start is correct but avoid this pattern: if a=b then true else false, instead just write a=b: So rewrite last line of start like this:

| starts (h1::t1) (h2::t2) = ((h1=h2) andalso (starts t1 t2));

Kevin Johnson
  • 1,890
  • 13
  • 15
  • I still don't understand how to correct the second line of contains, what would I use to loop through the second list? Would have to create a whole new function? If so, is there a way to keep it in just the single function? – madcrazydrumma Oct 03 '15 at 12:20
  • The solution is very simple. You are very close already. The second line should contain a if - else statement where you check for the conjunction: first element of both lists correspond andalso that starts evaluates to true from that point onwards. If this is the case, return true, else do contains of the remainder of the second_list. – Kevin Johnson Oct 03 '15 at 19:03
  • 1
    I've completed it! Thanks for the (pseudocode) help :) My final answer is: `fun contains l1 [] = false | contains l1 (hd::tl) = if(starts l1 (hd::tl)) then true else contains l1 tl;` – madcrazydrumma Oct 04 '15 at 11:35