[e-lang] Map Pattern Syntax (was: REST and capabilities (was Re:
Developing a capability security tools marketplace))
Mark S. Miller
e-lang@mail.eros-os.org
Tue, 06 Aug 2002 08:00:38 -0700
My answer to Ken below also provides background for my upcoming answer to Paul.
At 05:21 PM 8/5/2002 Monday, Ken Kahn wrote:
>> Mark S. Miller wrote:
>> >
>> > def makePoint(["x" => x, "y" => y] | _) :any { ... }
>> >
>
>Maybe it is too many years working with Prolog but shouldn't that be
>
>def makePoint(["x" => x, "y" => y | _]) :any { ... }
>
>?
It was inspired by that Prolog idiom for lists, so let's first look at lists.
Lisp lists have dotted notation:
(x y . rest)
Prolog-oids (Prolog, and other Herbrand-term-oriented horn clause languages,
like FCP) are the same in concept, but with different characters:
[x, y | rest]
In Prolog-oids, this syntax can be used both for expressions (in the body)
or for patterns (in the head).
E does something similar, but with a further pun. E is an expression
language with infix operators. In an expression context, we'd write:
[x, y] + rest
Unlike Lisps "." and Prolog-oid's "|", which are consing symbols, E's "+"
means append. Combined with the square bracket notation but put on the
outside, this enables consing to be expressed as easily as in Lisp or
Prolog, but enables other useful list construction expressions to be
expressed as easily:
[a, b] + midList + [x, y]
On the pattern side, E recognizes only the subset of this syntax
corresponding to cons. It will accept the first example but not the second
one.
? def [x, y] + rest := [1, 2, 3, 4]
# value: [1, 2, 3, 4]
? [rest, x, y]
# value: [[3, 4], 1, 2]
E's notation
["x" => 3, "y" => 7]
constructs a single-valued map, where for each key there is exactly one
value. Maps may be composed using the "|" operator
? def m := ["x" => 3, "y" => 7] | ["y" => 4, "z" => 9]
# value: ["y" => 7, "z" => 9, "x" => 3]
You can think of this as the union of the two maps, with the left map
dominating where they collide.
On the pattern side, 0.8.20 will accept the subset of this syntax which is
cons-like:
? def ["x" => x] | rest := m
# value: ["y" => 7, "z" => 9, "x" => 3]
? [x, rest]
# value: [3, ["y" => 7, "z" => 9]]
In a map pattern, each of the keys is an expression and each of the values
is a pattern. Execution and scoping proceeds strictly left-to-right, which
is normally the case in E, but was not immediately obvious how to achieve in
the expansion of this construct. The first key-expression is evaluated, the
first value is looked up. If found, it is matched against the first
value-pattern and the remaining map without this key-value association is
formed use starting at the next association. If there is a terminal "|
pattern", then it is matched against the final remaining map, without the
associations already matched. If there is no terminal "| rest", then the
expansion includes a test that the final remaining map is empty. If at any
step any lookup fails or any pattern match fails, then the match as a whole
fails.
----------------------------------------
Text by me above is hereby placed in the public domain
Cheers,
--MarkM