started on pattern matching
This commit is contained in:
parent
67cb7c7a30
commit
2efde48331
@ -13,3 +13,4 @@ with the language.
|
||||
itself. There's very few data structures, meaning there's minimal syntax.
|
||||
* [runtime](/doc/runtime.md) - How to structure your ginger data to be runnable by the ginger interpreter.
|
||||
Includes execution, variable definition, scope, and function definition.
|
||||
* [pattern matching](/doc/pattern.md) - Deconstruction of data structures and case statements on them.
|
||||
|
138
doc/pattern.md
Normal file
138
doc/pattern.md
Normal file
@ -0,0 +1,138 @@
|
||||
# Pattern Matching
|
||||
|
||||
Pattern matching in ginger is used both to assign variables and test for the contents of them.
|
||||
|
||||
## Assignment
|
||||
|
||||
The `=` function's job is to assign values to variables. In the simplest case:
|
||||
```
|
||||
(= Foo 5)
|
||||
```
|
||||
|
||||
Assigns the value `5` to the variable named `Foo`. We can assign more complicated values to variables
|
||||
as well:
|
||||
```
|
||||
(= Foo [1 2 3 4])
|
||||
```
|
||||
|
||||
### Deconstruction
|
||||
|
||||
With pattern matching, we can deconstruct the value on the right side and assign its individual parts
|
||||
to their own individual variables:
|
||||
```
|
||||
[
|
||||
(= [Foo Bar [Baz Box] Bus] [1 a [3 4] [5 6]])
|
||||
(println Foo)
|
||||
(println Bar)
|
||||
(println Baz)
|
||||
(println Box)
|
||||
(println Bus)
|
||||
]
|
||||
```
|
||||
|
||||
The above would print out:
|
||||
```
|
||||
1
|
||||
a
|
||||
3
|
||||
4
|
||||
[5 6]
|
||||
```
|
||||
|
||||
### No Match
|
||||
|
||||
What happens if we try to pattern match a value that doesn't match the left side?:
|
||||
```
|
||||
(= [Foo Bar Baz Box] [1 2 3]) ; => [error nomatch]
|
||||
```
|
||||
|
||||
The value itself is a vector with three items, but we want a vector with four! This returns an error
|
||||
and none of the variables were assigned.
|
||||
|
||||
### Blanks
|
||||
|
||||
If there's a variable we expect the right side to have, but we don't actually want to do anything with
|
||||
it, we can use `_`:
|
||||
```
|
||||
(= [Foo _ Baz] [1 2 3])
|
||||
```
|
||||
|
||||
The above would assign `1` to `Foo` and `2` to `Baz`.
|
||||
|
||||
### Left-side checks
|
||||
|
||||
The left side isn't exclusively used for assignment, it can also be used to check certain values on
|
||||
the right:
|
||||
```
|
||||
(= [1 Foo 2 Bar] [1 a 2 b]) ; => success
|
||||
(= [1 Foo 2 Bar] [1 a 3 b]) ; => [error nomatch]
|
||||
```
|
||||
|
||||
If a variable is already defined it can be used as a check as well:
|
||||
```
|
||||
[
|
||||
(= Foo 1)
|
||||
(= [Foo Foo Bar] [1 1 2]) ; => success
|
||||
(= [Foo Foo Baz] [1 2 3]) ; => [error nomatch]
|
||||
]
|
||||
```
|
||||
|
||||
Finally, undefined variables on the left side that are used more than once are ensured that all
|
||||
instances have the same value:
|
||||
```
|
||||
[
|
||||
(= [Foo Foo Foo] [foo foo foo]) ; => success
|
||||
(= [Bar Bar Bar] [foo bar bar]) ; => [error nomatch]
|
||||
]
|
||||
```
|
||||
|
||||
### Vectors
|
||||
|
||||
What if we don't know the full length of the vector, but we only want to retrieve the first two values
|
||||
from it?:
|
||||
```
|
||||
(= [Foo Bar -] [1 2 3 4 5])
|
||||
```
|
||||
|
||||
The above would assign `1` to `Foo` and `2` to `Bar`. `-` is treated to mean "zero or more items in the sequence
|
||||
that we don't care about".
|
||||
|
||||
What if you want to match on the tail end of the vector?:
|
||||
```
|
||||
(= [- Bar Foo] [1 2 3 4 5])
|
||||
```
|
||||
|
||||
The above would assign `4` to Bar and `5` to `Foo`.
|
||||
|
||||
Can we do both?:
|
||||
```
|
||||
(= [Foo - Bar] [1 2 3 4 5])
|
||||
```
|
||||
|
||||
The above would assign `1` to `Foo` and `5` to `Bar`.
|
||||
|
||||
### Lists
|
||||
|
||||
Everything that applies to vectors applies to lists, as far as pattern matching goes:
|
||||
```
|
||||
(= (Foo Bar Baz -) (l (foo bar baz)))
|
||||
```
|
||||
|
||||
In the above `foo` is assigned to `Foo`, `bar` to `Bar`, and `baz` to `Baz`.
|
||||
|
||||
Note that the right side needs the `l` literal wrapper to prevent evaluation, while
|
||||
the left side does not. Nothing on the left will ever be evaluated, if you want it
|
||||
to be dynamically defined you'll have to use a macro.
|
||||
|
||||
### Maps
|
||||
|
||||
Pattern matching can be performed on maps as well:
|
||||
```
|
||||
(= { Foo Bar } { a b }) ; => success
|
||||
(= { Foo Bar } { a b c d }) ; => [error nomatch]
|
||||
(= { Foo Bar - - } { a b c d }) ; => success
|
||||
```
|
||||
|
||||
In the last case, the important thing is that the key is `-`. This tells the matcher
|
||||
that you don't care about any other keys that may or may not exist. The value can be
|
||||
anything, but `-` seems semantically more correct imo.
|
@ -41,7 +41,7 @@ item in the vector. For (a trivial) example:
|
||||
The above example does a few things, but it repeats itself in the second part (with the `sub`). If we could save the
|
||||
result of the addition to a variable that would be awesomesauce. The `=` function does this! It makes it so that the
|
||||
first argument is equivalent to the evaluation of the second argument. Variables' can not be re-defined to be another
|
||||
value, and their first letters must be upper-case, thisis how they're differentiated from raw string literals.The above
|
||||
value, and their first letters must be upper-case, this is how they're differentiated from raw string literals.The above
|
||||
could be re-written as:
|
||||
```
|
||||
[ (= AdditionResult (add 1 2))
|
||||
|
Loading…
Reference in New Issue
Block a user