v0.0.10: hide record fields & union variants, extensible unions, lenses
This commit is contained in:
96
spec.md
96
spec.md
@@ -73,6 +73,7 @@ all operators:
|
|||||||
- `List[t] ++ List[t]`: list concatenation
|
- `List[t] ++ List[t]`: list concatenation
|
||||||
- `value :: t` (explicitly specify type of value, useful for down-casting structs, or just code readability; does not perform casting)
|
- `value :: t` (explicitly specify type of value, useful for down-casting structs, or just code readability; does not perform casting)
|
||||||
- `list[index]`
|
- `list[index]`
|
||||||
|
- `a => b`: lens compose
|
||||||
|
|
||||||
## non-nominal struct types
|
## non-nominal struct types
|
||||||
```
|
```
|
||||||
@@ -80,6 +81,10 @@ all operators:
|
|||||||
type User = { name: List[Char] }
|
type User = { name: List[Char] }
|
||||||
type DbUser = { name: List[Char], pass: List[Char] }
|
type DbUser = { name: List[Char], pass: List[Char] }
|
||||||
|
|
||||||
|
def example4(u: User) : List[Char] {
|
||||||
|
u:name # colon is used to access fields
|
||||||
|
}
|
||||||
|
|
||||||
def example(u: User) : DbUser {
|
def example(u: User) : DbUser {
|
||||||
u with pass: "1234"
|
u with pass: "1234"
|
||||||
# has type { name: List[Char], pass: List[Char] }
|
# has type { name: List[Char], pass: List[Char] }
|
||||||
@@ -245,18 +250,18 @@ Export signature file `List.li`:
|
|||||||
type List[t] = 'End | 'Cons {head:t, tail:List[t]}
|
type List[t] = 'End | 'Cons {head:t, tail:List[t]}
|
||||||
|
|
||||||
# not providing a function body makes it a function signature definition
|
# not providing a function body makes it a function signature definition
|
||||||
def [t] `a++b`(a: List[t], b: List[t]) -> List[t];
|
def [t] `a++b`(a: List[t], b: List[t]) -> List[t]
|
||||||
|
|
||||||
def [t] Match.`a++b`(
|
def [t] Match.`a++b`(
|
||||||
value: List[t],
|
value: List[t],
|
||||||
l: List[t],
|
l: List[t],
|
||||||
r: MatchUtil.Var[List[t]]
|
r: MatchUtil.Var[List[t]]
|
||||||
) -> Option[{ r: List[t] }];
|
) -> Option[{ r: List[t] }]
|
||||||
```
|
```
|
||||||
|
|
||||||
Import signature file `Option.li`:
|
Import signature file `Option.li`:
|
||||||
```
|
```
|
||||||
type Option[t] = 'None | 'Some t;
|
type Option[t] = 'None | 'Some t
|
||||||
```
|
```
|
||||||
|
|
||||||
Compilation unit `List.lu`:
|
Compilation unit `List.lu`:
|
||||||
@@ -279,4 +284,87 @@ Each compilation unit gets compiled to implementation-specific bytecode.
|
|||||||
|
|
||||||
Templated functions can only be compiled partially during a compilation unit. This will impact compile speeds.
|
Templated functions can only be compiled partially during a compilation unit. This will impact compile speeds.
|
||||||
|
|
||||||
Avoid templated functions wherever possible.
|
Avoid templated functions wherever possible.
|
||||||
|
|
||||||
|
## Hide record fields in module signatures
|
||||||
|
Signatue:
|
||||||
|
```
|
||||||
|
type User = {name: List[Char], ...}
|
||||||
|
# the ... is used to indicate that this is a partial type definition
|
||||||
|
# User, as given here, can not be constructed, but name can be accessed
|
||||||
|
```
|
||||||
|
Compilation unit:
|
||||||
|
```
|
||||||
|
type User = {name: List[Char], password: List[Char]}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hide union variants in module signatures
|
||||||
|
Signature:
|
||||||
|
```
|
||||||
|
type DType = 'Int | 'UInt | 'Byte | ...
|
||||||
|
# users of this can never do exhaustive pattern matching on this
|
||||||
|
```
|
||||||
|
Compilation unit:
|
||||||
|
```
|
||||||
|
type DType = 'Int | 'UInt | 'Byte
|
||||||
|
# this compilation unit can actually do exhaustive pattern matching on this
|
||||||
|
```
|
||||||
|
|
||||||
|
## Note on hidden union variants / record fields
|
||||||
|
To make these work, the following is legal:
|
||||||
|
```
|
||||||
|
def example() -> 'Int | 'UInt | ...
|
||||||
|
|
||||||
|
def example() -> 'Int | 'UInt | 'Byte | 'Char {
|
||||||
|
# ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extensible unions
|
||||||
|
```
|
||||||
|
type Plan = dyn 'Plan;
|
||||||
|
# ^ this is not a union variant tag, but a quoted identifier
|
||||||
|
|
||||||
|
extend Plan with 'ReadlnPlan
|
||||||
|
extend Plan with 'WritelnPlan
|
||||||
|
|
||||||
|
# pattern matching against these is always non-exhaustive.
|
||||||
|
# can only pattern match with the imported extensions
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Lenses
|
||||||
|
In the stdlib:
|
||||||
|
```
|
||||||
|
type Lens[t,f] = {get: t -> f, set: t -> f -> t}
|
||||||
|
|
||||||
|
def [a,b,c] `a=>b`(x: Lens[a,b], y: Lens[b,c]) -> Lens[a,c] {
|
||||||
|
{
|
||||||
|
get: t:a -> y:get(x:get(t)),
|
||||||
|
set: t:a -> f:c -> x:set(t, y:set(x:get(t), f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Since `a:f1:f2` is the field access syntax, the lens creation syntax is similar: `&Type:field1:field2`
|
||||||
|
|
||||||
|
So you can do:
|
||||||
|
```
|
||||||
|
type Header = {text: String, x: Num}
|
||||||
|
type Meta = {header: Header, name: String}
|
||||||
|
|
||||||
|
&Header:header:text (myHeader, "new meta:header:text value")
|
||||||
|
# which is identical to:
|
||||||
|
(&Header:header => &Meta:text) (myHeader, "new meta:header:text value")
|
||||||
|
```
|
||||||
|
|
||||||
|
However, it is cleaner to use `with`:
|
||||||
|
```
|
||||||
|
myHeader with header:text: "new meta:header:text value"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Pure IO
|
||||||
|
```
|
||||||
|
TODO
|
||||||
|
```
|
Reference in New Issue
Block a user