0

How can I have multiple case statements which do not interleave with each other. A toy example for instance:

 fun multi_cases(xs) =
     case xs of
       [] => 5
      | x::ys => case x of
                    1 => 2
                   |_ => 3
      | x::[] => case x of
                    1 => 5
                    | _ => 7
 ;

stdIn:59.17-64.28 Error: types of rules don't agree [overload conflict]
  earlier rule(s): [int ty] -> [int ty]
  this rule: [int ty] list -> [int ty]
  in rule:
    :: (x,nil) =>
      (case x
        of 1 => 5
         | _ => 7)

The last two case statements are getting mixed up how can I tell SML that they are indeed two independent case statements rather than a continuation/separate branch of case x of 1 => 2 ...

The patterns above as pointed in the answer below have an issue with their generality.

Har
  • 3,727
  • 10
  • 41
  • 75
  • Possible duplicate of [Nested case statements in SML](http://stackoverflow.com/questions/14708732/nested-case-statements-in-sml) – John Coleman Feb 10 '17 at 01:34

1 Answers1

2

This code has two distinct problems:

  1. As the question Nested case statements in SML that John links to says, case-ofs are a little tricky syntactically because their list of case statements never "stops". That is, your code actually gets parsed as:

    fun multi_cases xs =
        case xs of
             [] => 5
           | x::ys => case x of
                           1 => 2
                         | _ => 3
                         | x::[] => case x of
                                         1 => 5
                                       | _ => 7
    

    which is nonsensical because that third pattern should have belonged to the outer case-of and not the inner (the inner case-of deals with x as an int, and the outer with x::[] as an int list).

    Since your indentation does not actively help the compiler towards the intended meaning, using parentheses to "stop" the case-ofs from intertwining, like that post says, is the fix:

    fun multi_cases xs =
        case xs of
             [] => 5
           | x::ys => (case x of
                           1 => 2
                         | _ => 3)
           | x::[] => (case x of
                            1 => 5
                          | _ => 7)
    

    Alternatively you could turn the outer case-of into a match on the function's arguments itself and blend the inner case-of together with it, since a single pattern match allows for arbitrarily deep matching:

    fun fun_cases [] = 5
      | fun_cases [1] = 5
      | fun_cases [_] = 7
      | fun_cases (1::_) = 2
      | fun_cases (_::_) = 3
    
  2. Your two cases overlap because x::xs is a more general pattern than x::[]. That is, it also covers the list x::[] by setting xs to []. You could fix that in one of two ways:

    1. List the least general pattern first, e.g.

      case xs of
           [] => 5
         | [x] => ...
         | x::_ => ...
      
    2. Make that x::xs general pattern into a less general one by specifying that the list should have at least two elements:

      case xs of
           x :: _ :: _ => ...
         | [x] => ...
         | [] => ...
      
Community
  • 1
  • 1
sshine
  • 15,635
  • 1
  • 41
  • 66
  • What do these brackets do? Do they add in some kind of pattern matching? – Har Feb 10 '17 at 12:14
  • +1 question, is there a rule in the language which would help you define the more general patterns first? As the less general patterns would not match. – Har Feb 10 '17 at 15:57
  • What brackets? I'm not sure what you mean by rules in the language. Stack Overflow isn't really suitable for forth-and-back discussion in the commentary, or for continuous elaboration on sub-questions. I'd recommend you read an [entry-level book on Standard ML](https://www.amazon.com/Introduction-Programming-International-Computer-Science/dp/0201398206), take a course that has TAs, or read about specific subjects, such as [type inference/unification](http://www.cs.cornell.edu/courses/cs312/2005sp/lectures/lec22.asp). – sshine Feb 11 '17 at 00:54