Reputation: 41
I have two custom datatypes,
datatype expression = Constant of int
| Variable of string
| Operator of string * expression
| Pair of expression list
| List of expression list
datatype pattern = ConstantP of int
| VariableP of string
| OperatorP of string * pattern
| PairP of pattern list
| ListP of pattern list
| UnorderedListP of pattern list
| Wildcard
I should implement a function
match (fn : expression * pattern -> (string * expression) list option)
that gets an expression and a pattern. If match is possible, it returns SOME (list of bindings)
, otherwise it returns NONE
.
Matching should be done in this way:
A match is defined on a tuple of an expression and a list (expression * pattern). Expression and Pattern can either match or not. If they do, the match produces a list of bindings - pairs of names and values ((string * expression) list), the ordering of the list does not matter. Matching uses the following rules:
If you could give me some tips in which direction to go, i think that my function should be something like this I guess, but not sure hot to cover all cases recursively
fun match(e: expression, p: pattern) : (string * expression) list option =
case p of
Wildcard => SOME []
| VariableP s => ...
Upvotes: 1
Views: 1791
Reputation: 66371
Use more pattern matching.
Then you go through the list of rules one by one and translate them, recursing when the rule depends on a sub-match.
You only need to define the cases of matching constructors, leaving the mismatches for the last, default, case.
fun match (_, Wildcard) = SOME []
| match (Constant x, ConstantP y) = if x = y then SOME [] else NONE
| match (Pair [p1, p2], PairP [p1', p2']) =
let
val match1 = match (p1, p1')
in case match1 of
NONE => NONE
| SOME ls => ...
end
| ...
| match _ = NONE
but you can make things more convenient by defining some helper functions.
(The Pair
clause above gets unwieldy once you type all of it in.)
For example, concatenating two optional lists only if neither is NONE
can be written very concisely as a function:
fun appendOptional (SOME xs, SOME ys) = SOME (xs @ ys)
| appendOptional _ = NONE
and lets you write a single line
| match (Pair[p1, p2], PairP[p1', p2']) = appendOptional(match(p1, p1'), match(p2, p2'))
and that function may come in handy in other situations as well.
(The list rules are painful, if not impossible, to write without helper functions.)
A more elaborated example:
datatype expression = Constant of int
| Variable of string
| Pair of expression list
datatype pattern = ConstantP of int
| VariableP of string
| PairP of pattern list
| Wildcard
fun appendOptional (SOME xs, SOME ys) = SOME (xs @ ys)
| appendOptional _ = NONE
fun match (_, Wildcard) = SOME []
| match (Constant x, ConstantP y) = if x = y then SOME [] else NONE
| match (Pair [p1, p2], PairP [p1', p2']) = appendOptional (match (p1, p1'), match (p2, p2'))
| match (e, VariableP v) = SOME [(v, e)]
| match _ = NONE
Test:
- match (Constant 32, ConstantP 1);
val it = NONE : (string * expression) list option
- match (Constant 32, ConstantP 32);
val it = SOME [] : (string * expression) list option
- match (Constant 32, VariableP "x");
val it = SOME [("x",Constant 32)] : (string * expression) list option
- match (Pair [Constant 32, Variable "y"], PairP [VariableP "a", VariableP "b"]);
val it = SOME [("a",Constant 32),("b",Variable "y")]
: (string * expression) list option
Upvotes: 2