v0.0.10: hide record fields & union variants, extensible unions, lenses

This commit is contained in:
2025-09-12 12:03:29 +02:00
parent f9a2babf95
commit 7e8739cdd8

96
spec.md
View File

@@ -73,6 +73,7 @@ all operators:
- `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)
- `list[index]`
- `a => b`: lens compose
## non-nominal struct types
```
@@ -80,6 +81,10 @@ all operators:
type User = { name: 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 {
u with pass: "1234"
# 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]}
# 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`(
value: List[t],
l: List[t],
r: MatchUtil.Var[List[t]]
) -> Option[{ r: List[t] }];
) -> Option[{ r: List[t] }]
```
Import signature file `Option.li`:
```
type Option[t] = 'None | 'Some t;
type Option[t] = 'None | 'Some t
```
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.
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
```