Update spec.md

This commit is contained in:
2025-09-16 07:17:25 +02:00
parent ecc037415b
commit 13f73fbee3

198
spec.md
View File

@@ -409,28 +409,85 @@ Give fuzzy-matched suggestions for at the following things:
## Store as much debug in fromation as possible until type checking is done
# Compilation units
Each file is a "compilation unit"
When compiling a compilation unit, the following inputs have to be provided:
- any amount of files containing signatures of exported definitions.
only definitions of the compilation unit that are in one of the signature files will get exported.
- any amount of other files containing imported definitions
Note that there is no practical difference between signature and source files.
<details>
<summary>Example</summary>
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]
```
Import signature file `Option.li`:
```
type Option[t] = 'None | 'Some t
```
Compilation unit `List.lu`:
```
def [t] `a++b`(a: List[t], b: List[t]) -> List[t] {
# ...
}
```
</details>
# Syntax
Note that the order of syntax cases matter!
```
Identifier = { (* ( a-z | A-Z | 0-9 | _ | - | . | # ) TODO: cvt to ebnf *) };
Partial Type = '?', Identifier;
Union Type Case = '\'', Identifier, [ Type (*default to Unit*) ];
Union Type = Union Type Case, { '|', Union Type Case};
Record Type Field = Identifier, ':', Type;
Record Type = '{', [Record Type Field, {',' Record Type Field }], [ '...', Partial Type ], '}';
Type = Partial Type | Identifier | Union Type | Record Type | TODO;
With Type = 'with', Identifier, {',', Identifier}, ':', Type;
Recursive Type = '&', Identifier, Type;
Nested Type = '(', Type, ')';
Multi Arg Type = '[', Type, {',', Type} ']', Type;
Auto Type = '_'; (* this only works as return type of signatures of func def, that also contain the impl *)
Type Part = Auto Type | Identifier | Partial Type | Union Type | Record Type | With Type | Recursive Type | Nested Type;
Type = {Type Part (* args *)}, Type Part;
```
# OLD SPECIFICATION STARTING HERE
## automatic return types
```
def add(a: Num, b: Num) -> _ {
a + b
}
```
## pattern matching
```
type Option[t] = 'None | 'Some t
@@ -462,121 +519,7 @@ def example(li: List[Char]) -> {t:Token,rem:List[Char]} {
}
```
## recursive data types
```
type List[t] = 'End | 'Cons {head:t, tail:List[t]}
# now you might notice an issue with this
# `type` defines non-distinct type alisases
# so what is the type of this...
# Introducing: type self references
# the above example is the same as this:
type List[t] = &a ('End | 'Cons {head:t, tail:a})
# example 2:
# a List[List[t]] is just:
&b ('End | 'Cons {head: &a ('End | 'Cons {head:t, tail:a}), tail: b})
```
Infinitely sized types are not allowed:
```
&a {x:Num, y:a}
```
However, infinite types without size *are* allowed:
```
&a {x:a}
```
This is *not* allowed:
```
&a a
```
## module system
Each file is a "compilation unit"
When compiling a compilation unit, the following inputs have to be provided:
- any amount of files containing signatures of exported definitions.
only definitions of the compilation unit that are in one of the signature files will get exported.
- any amount of other files containing imported definitions
Note that there is no practical difference between signature and source files.
### Example
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] Match.`a++b`(
value: List[t],
l: List[t],
r: MatchUtil.Var[List[t]]
) -> Option[{ r: List[t] }]
```
Import signature file `Option.li`:
```
type Option[t] = 'None | 'Some t
```
Compilation unit `List.lu`:
```
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] }] {
# ...
}
```
### Notes
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.
## 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
```
@@ -589,17 +532,6 @@ extend Plan with 'WritelnPlan Unit
# can only pattern match with the imported extensions
```
## Any type
in the stdlib:
```
extensible union Any
type Any.LambdaCalc = 'Apply {fn: Any.LambdaCalc, arg: Any.LambdaCalc}
| 'Scope {idx: Uint}
| 'Abstr {inner: Any.LambdaCalc}
def Any.toLambda(a: Any) -> Any.LambdaCalc
```
It gets automatically extended with every type ever used.
## Lenses
In the stdlib: