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.
|
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.
|
* [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.
|
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.
|
Loading…
Reference in New Issue
Block a user