Home > Mobile >  How do you see if adjacent elements repeat in a list? (SML)
How do you see if adjacent elements repeat in a list? (SML)

Time:02-21

SML is a challenging language for me to learn. I'm trying to find a way to screen an undetermined list and return a boolean based on whether two elements adjacent on a list are the same value or not. What I've tried and think is close to correct is below.

fun repeatE nil = false
  | repeatE (first::last) = first = last orelse repeatsE(last);

Obviously, this results in an error. I based my answer on this code, which tells me if a value is an element in the list.

fun member (e, nil) = false
  | member (e, first::last) = e = first orelse member(e, last);

Why does the first one not work, but the last one does? It tells me that the operator and the operand don't agree, and maybe I'm thick-headed, but I don't quite understand why they don't?

Thank you in advance!

CodePudding user response:

first=last tries to compare the first element of a list with the tail of that list, and you can only compare things of the same (comparable) type.

The working code works because it doesn't try to compare a list element to an entire list.

You need to compare the first element to the second element, and you need to handle the case of a singleton list.

Something like this:

fun repeats nil = false
  | repeats (first::rest) = case rest of 
                               (x::xs) => first = x orelse repeats rest
                           |   _ => false

or

fun repeats nil = false
  | repeats (first::rest) = not (null rest)
                            andalso (first = (hd rest) orelse repeats rest)

CodePudding user response:

It's actually possible to use as to clean up @molbdnilo's answer a fair bit.

Ask yourself: An empty list is false, but so is a list with a single element, right?

fun repeats([])  = false
  | repeats([_]) = false

Now, we need to match a list with at least two elements, and compare those. If they're not equal, we'll check everything but the first element.

fun repeats([])  = false
  | repeats([_]) = false
  | repeats(a::b::tail) =   
      a = b orelse repeats(b::tail)

But we don't need to use b::tail.

fun repeats([])  = false
  | repeats([_]) = false
  | repeats(a::(tail as b::_)) =   
      a = b orelse repeats(tail)

If we want, we can recognize that the empty list and the single element list are just the "other" when the last pattern doesn't match, and we'll rewrite it to reflect that.

fun repeats(a::(tail as b::_)) = 
      a = b orelse repeats(tail)
  | repeats(_) = false
  • Related