Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple Patterns in 1 case

Tags:

sml

smlnj

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")
like image 685
rlhh Avatar asked Apr 01 '16 03:04

rlhh


3 Answers

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
like image 75
Ionuț G. Stan Avatar answered Oct 16 '22 21:10

Ionuț G. Stan


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 ...
like image 2
sshine Avatar answered Oct 16 '22 21:10

sshine


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
;
like image 2
Jemenake Avatar answered Oct 16 '22 20:10

Jemenake