Multiple Patterns in 1 case

2019-02-24 09:40发布

问题:

In SML, is it possible for you to have multiple patterns in one case statement?

For example, I have 4 arithmetic operators express in string, "+", "-", "*", "/" and I want to print "PLUS MINUS" of it is "+" or "-" and "MULT DIV" if it is "*" or "/".

TL;DR: Is there somewhere I can simplify the following to use less cases?

case str of
   "+" => print("PLUS MINUS")
 | "-" => print("PLUS MINUS")
 | "*" => print("MULT DIV")
 | "/" => print("MULT DIV")

回答1:

Given that you've tagged your question with the smlnj tag, then yes, SML/NJ supports this kind of patterns. They call it or-patterns and it looks like this:

case str of
  ("+" | "-") => print "PLUS MINUS"
| ("*" | "/") => print "MULT DIV"

Notice the parentheses.

The master branch of MLton supports it too, as part of their Successor ML effort, but you'll have to compile MLton yourself.

val str = "+"

val _ =
  case str of
    "+" | "-" => print "PLUS MINUS"
  | "*" | "/" => print "MULT DIV"

Note that MLton does not require parantheses. Now compile it using this command (unlike SML/NJ, you have to enable this feature explicitly in MLton):

mlton -default-ann 'allowOrPats true' or-patterns.sml


回答2:

In Standard ML, no. In other dialects of ML, such as OCaml, yes. You may in some cases consider splitting pattern matching up into separate cases/functions, or skip pattern matching in favor of a shorter catch-all expression, e.g.

if str = "+" orelse str = "-" then "PLUS MINUS" else
if str = "*" orelse str = "/" then "MULT DIV" else ...


回答3:

Expanding upon Ionuț's example, you can even use datatypes with other types in them, but their types (and identifier assignments) must match:

datatype mytype = COST as int | QUANTITY as int | PERSON as string | PET as string;

case item of
  (COST n|QUANTITY n) => print Int.toString n
  |(PERSON name|PET name) => print name

If the types or names don't match, it will get rejected:

case item of
  (COST n|PERSON n) => (* fails because COST is int and PERSON is string *)
  (COST n|QUANTITY q) => (* fails because the identifiers are different *)

And these patterns work in function definitions as well:

fun myfun (COST n|QUANTITY n) = print Int.toString n
   |myfun (PERSON name|PET name) = print name
;


标签: sml smlnj