init commit again
This commit is contained in:
224
IBAF-cbs/Funcons-beta/Values/Abstraction/Patterns/Patterns.cbs
Normal file
224
IBAF-cbs/Funcons-beta/Values/Abstraction/Patterns/Patterns.cbs
Normal file
@@ -0,0 +1,224 @@
|
||||
### Patterns
|
||||
|
||||
[
|
||||
Datatype patterns
|
||||
Funcon pattern
|
||||
Funcon pattern-any
|
||||
Funcon pattern-bind
|
||||
Funcon pattern-type
|
||||
Funcon pattern-else
|
||||
Funcon pattern-unite
|
||||
Funcon match
|
||||
Funcon match-loosely
|
||||
Funcon case-match
|
||||
Funcon case-match-loosely
|
||||
Funcon case-variant-value
|
||||
]
|
||||
|
||||
/*
|
||||
General patterns are simple patterns or structured patterns.
|
||||
Matching a pattern to a value either computes an environment or fails.
|
||||
|
||||
Simple patterns are constructed from abstractions whose bodies depend on
|
||||
a given value, and whose executions either compute environments or fail.
|
||||
|
||||
Structured patterns are composite values whose components may include
|
||||
simple patterns as well as other values.
|
||||
|
||||
Matching a structured value to a structured pattern is similar to assigning
|
||||
a structured value to a structured variable, with simple pattern components
|
||||
matching component values analogously to simple variable components assigned
|
||||
component values.
|
||||
|
||||
Note that patterns match only values, not (empty or proper) sequences.
|
||||
*/
|
||||
|
||||
|
||||
Meta-variables
|
||||
T, T' <: values
|
||||
|
||||
|
||||
#### Simple patterns
|
||||
|
||||
Datatype
|
||||
patterns ::= pattern(_:abstractions(values=>environments))
|
||||
/*
|
||||
`patterns` is the type of simple patterns that can match values of a
|
||||
particular type.
|
||||
|
||||
`pattern(abstraction(X))` constructs a pattern with dynamic bindings, and
|
||||
`pattern(closure(X))` computes a pattern with static bindings. However,
|
||||
there is no difference between dynamic and static bindings when the pattern
|
||||
is matched in the same scope where it is constructed.
|
||||
*/
|
||||
|
||||
|
||||
Funcon
|
||||
pattern-any : =>patterns
|
||||
~> pattern(abstraction(map( )))
|
||||
/*
|
||||
`pattern-any` matches any value, computing the empty environment.
|
||||
*/
|
||||
|
||||
|
||||
Funcon
|
||||
pattern-bind(I:identifiers) : =>patterns
|
||||
~> pattern(abstraction(bind-value(I, given)))
|
||||
/*
|
||||
`pattern-bind(I)` matches any value, computing the environment binding `I`
|
||||
to that value.
|
||||
*/
|
||||
|
||||
|
||||
Funcon
|
||||
pattern-type(T) : =>patterns
|
||||
~> pattern(abstraction(if-true-else(is-in-type(given, T), map( ), fail)))
|
||||
/*
|
||||
`pattern-type(T)` matches any value of type `T`, computing the empty
|
||||
environment.
|
||||
*/
|
||||
|
||||
|
||||
Funcon
|
||||
pattern-else(_:values, _:values) : =>patterns
|
||||
Rule
|
||||
pattern-else(P1:values, P2:values)
|
||||
~> pattern(abstraction(else(match(given, P1), match(given, P2))))
|
||||
/*
|
||||
`pattern-else(P1, P2)` matches all values matched by `P1` or by `P2`.
|
||||
If a value matches `P1`, that match gives the computed environment;
|
||||
if a value does not match `P1` but matches `P2`, that match gives
|
||||
the computed environment; otherwise the match fails.
|
||||
*/
|
||||
|
||||
|
||||
Funcon
|
||||
pattern-unite(_:values, _:values) : =>patterns
|
||||
Rule
|
||||
pattern-unite(P1:values, P2:values)
|
||||
~> pattern(abstraction(collateral(match(given, P1), match(given, P2))))
|
||||
/*
|
||||
`pattern-unite(P1, P2)` matches all values matched by both `P1` and `P2`,
|
||||
then uniting the computed environments, which fails if the domains of the
|
||||
environments overlap.
|
||||
*/
|
||||
|
||||
|
||||
#### Pattern matching
|
||||
|
||||
Funcon
|
||||
match(_:values, _:values) : =>environments
|
||||
/*
|
||||
`match(V, P)` takes a (potentially structured) value `V` and a
|
||||
(potentially structured) pattern `P`. Provided that the structure and all
|
||||
components of `P` exactly match the structure and corresponding components
|
||||
of `V`, the environments computed by the simple pattern matches are united.
|
||||
*/
|
||||
Rule
|
||||
match(V:values, pattern(abstraction(X))) ~> give(V, X)
|
||||
Rule
|
||||
I2 =/= "pattern"
|
||||
--------------------------------------------
|
||||
match(datatype-value(I1:identifiers, V1*:values*),
|
||||
datatype-value(I2:identifiers, V2*:values*))
|
||||
~> sequential(
|
||||
check-true(is-equal(I1, I2)),
|
||||
check-true(is-equal(length V1*, length V2*)),
|
||||
collateral(interleave-map(
|
||||
match(tuple-elements(given)),
|
||||
tuple-zip(tuple(V1*), tuple(V2*)))))
|
||||
Rule
|
||||
dom(M2) == {}
|
||||
------------------------------------------------------
|
||||
match(M1:maps(_,_), M2:maps(_,_))
|
||||
~> if-true-else(is-equal(dom(M1), {}), map( ), fail)
|
||||
Rule
|
||||
dom(M2) =/= {}
|
||||
some-element(dom(M2)) ~> K
|
||||
-------------------------------------------------------
|
||||
match(M1:maps(_,_), M2:maps(_,_))
|
||||
~> if-true-else(
|
||||
is-in-set(K, dom(M1)),
|
||||
collateral(
|
||||
match(map-lookup(M1, K), map-lookup(M2, K)),
|
||||
match(map-delete(M1, {K}), map-delete(M2, {K}))),
|
||||
fail)
|
||||
Rule
|
||||
P : ~(datatype-values|maps(_,_))
|
||||
-----------------------------------------------
|
||||
match(V:values, P:values)
|
||||
~> if-true-else(is-equal(V, P), map( ), fail)
|
||||
|
||||
|
||||
Funcon
|
||||
match-loosely(_:values, _:values) : =>environments
|
||||
/*
|
||||
`match-loosely(V, P)` takes a (potentially structured) value `V` and a
|
||||
(potentially structured) pattern `P`. Provided that the structure and all
|
||||
components of `P` loosely match the structure and corresponding components
|
||||
of `V`, the environments computed by the simple pattern matches are united.
|
||||
*/
|
||||
Rule
|
||||
match-loosely(V:values, pattern(abstraction(X))) ~> give(V, X)
|
||||
Rule
|
||||
I2 =/= "pattern"
|
||||
---------------------------------------------------
|
||||
match-loosely(datatype-value(I1:identifiers, V1*:values*),
|
||||
datatype-value(I2:identifiers, V2*:values*))
|
||||
~> sequential(
|
||||
check-true(is-equal(I1, I2)),
|
||||
check-true(is-equal(length V1*, length V2*)),
|
||||
collateral(interleave-map(
|
||||
match-loosely(tuple-elements(given)),
|
||||
tuple-zip(tuple(V1*), tuple(V2*)))))
|
||||
Rule
|
||||
dom(M2) == {}
|
||||
-------------------------------------------------
|
||||
match-loosely(M1:maps(_,_), M2:maps(_,_)) ~> map()
|
||||
Rule
|
||||
dom(M2) =/= {}
|
||||
some-element(dom(M2)) ~> K
|
||||
--------------------------------------------------------------
|
||||
match-loosely(M1:maps(_,_), M2:maps(_,_))
|
||||
~> if-true-else(
|
||||
is-in-set(K, dom(M1)),
|
||||
collateral(
|
||||
match-loosely(map-lookup(M1, K), map-lookup(M2, K)),
|
||||
match-loosely(map-delete(M1, {K}), map-delete(M2, {K}))),
|
||||
fail)
|
||||
Rule
|
||||
P : ~(datatype-values|maps(_,_))
|
||||
-------------------------------------------
|
||||
match-loosely(DV:values, P:values)
|
||||
~> if-true-else(is-equal(DV, P), map( ), fail)
|
||||
|
||||
|
||||
Funcon
|
||||
case-match(_:values, _:=>T') : =>T'
|
||||
/*
|
||||
`case-match(P, X)` matches `P` exactly to the given value.
|
||||
If the match succeeds, the computed bindings have scope `X`.
|
||||
*/
|
||||
Rule
|
||||
case-match(P:values, X) ~> scope(match(given, P), X)
|
||||
|
||||
|
||||
Funcon
|
||||
case-match-loosely(_:values, _:=>T') : =>T'
|
||||
/*
|
||||
`case-match(P, X)` matches `P` loosely to the given value.
|
||||
If the match succeeds, the computed bindings have scope `X`.
|
||||
*/
|
||||
Rule
|
||||
case-match-loosely(P:values, X) ~> scope(match-loosely(given, P), X)
|
||||
|
||||
|
||||
Funcon
|
||||
case-variant-value(_:identifiers) : =>values
|
||||
/*
|
||||
`case-variant-value(I)` matches values of variant `I`, then
|
||||
giving the value contained in the variant.
|
||||
*/
|
||||
Rule
|
||||
case-variant-value(I:identifiers) ~>
|
||||
case-match(variant(I, pattern-any), variant-value(given))
|
||||
Reference in New Issue
Block a user