This commit is contained in:
2025-09-12 10:08:47 +02:00
parent ffd888a821
commit 0d3305f68d

168
spec.md Normal file
View File

@@ -0,0 +1,168 @@
## Arithmetic
```
1.2 * 4 + 1
(* result: 5.8 *)
```
## Few types to learn
Most important ones:
- `Num`: big-decimal
- `List[T]`: (linked-) list of `T`
- `Char`: unicode codepoint
- `Unit`: nothing
- `End`: unreachable
- `Cell[T]`: mutable cell of `T`
Advanced (uncommon) types:
- `Int8`, `Int16`, ...
- `Uint8`, ...
- `Flt32`, `Flt64`
## Functions
```
def msg(username: List[Char]) : List[Char] {
"Hello, " ++ username ++ "!" (* last expr is returned *)
}
def main() {
print("hi")
}
main()
```
## Simple, forward type-inference
```
def zero () : Flt32 {
3.1 (* error: got Num, but expected F32 *)
}
```
## Bindings
```
let name = "Max"
let passw = "1234"
```
## Mutability only via `ref`
```
let value = Cell.from(1)
print(Num.to_str(!value)) (* !cell "observes" the cell *)
value := 2 (* `:=` mutates the cell *)
print(Num.to_str(!value))
```
## (Almost) no function or operator overloading
all operators:
- `Num + Num` (has overloads for fixed width number types)
- `Num - Num` (has overloads for fixed width number types)
- `Num * Num` (has overloads for fixed width number types)
- `Num / Num` (has overloads for fixed width number types)
- `Num ^ Num`: raise to the power (has overloads for fixed width number types)
- `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]`
- `!cell`: "observe" a mutable value
- `cell := value`: mutate a mutable value
## non-nominal struct types
```
(* `type` creates a non-distinct type alias *)
type User = { name: List[Char] }
type DbUser = { name: List[Char], pass: List[Char] }
def example(u: User) : DbUser {
u with pass: "1234"
(* has type { name: List[Char], pass: List[Char] } *)
}
def example2() : {name: List[Char], pass: List[Char]} {
{name:"abc", pass:"123"}
}
def example3() : User {
example2() (* {name:.., pass:...} can automatically decay to {name:...} *)
}
```
## mixed-tagged union types
```
type Option[t] =
'Err Unit (* Unit that has tag enum 'Err *)
| t (* has no tag *)
(* the tags of unions are weakly attached to the types, but won't decay unless they have to *)
def example(n: Num) : Num {
let x = 'MyTag n (* type of x is 'MyTag Num *)
x (* tag gets removed because target type is Num *)
}
def example2(n: Num) : Option[Num] {
n (* this works, because the `t` is not tagged in option *)
}
def example3-invalid() : Option[Num] {
Unit (* error: can't convert type `Unit` into type `'Err Unit | t`
* Either label the expression with 'Err,
* or change the return type to Option[Unit] *)
}
def exampe4(): Option[Num] {
'Err Unit
(* type of this expression is: `'Err Unit` *)
(* enums can automatically cast, if all the cases from the source enum also exists in the target enum,
* which they do here: `'Err Unit` is a case in `'Err Unit | Num` *)
}
def example5-error(): Option[Num] {
let x = ( 'Err Unit ) :: Option[Unit]
x
(* error: can't convert type `'Err Unit | Unit` into type `'Err Unit | Num`
* The case `Unit` does not exist in the target `'Err Unit | Num` *)
}
def example6-error(): Option[Unit] {
let x = 'Error Unit
x
(* in this case, the enum tag does not decay, like in `example`,
* because we are casting to an enum *)
(* error: can't convert type `'Error Unit` into type `'Err Unit | Num``
* 1st possible solution: manually cast to just `Unit` (via `expr :: Unit`), so that it can convert to the second case of the target
* 2nd possible solution: pattern match against the enum, to rename the tag from 'Error to 'Err *)
}
```
## pattern matching
```
type Option[t] = 'None | 'Some t
def [t] Match.`a++b`(
(* matching against this value *)
value: List[t],
(* left hand side of operator *)
l: List[t],
(* right hand side of operator *)
r: MatchUtil.Var[List[t]]
) -> Option[{ r: List[t] }] {
match List.remove_prefix(l, 'from value) {
'Some rem -> 'Some { r: rem }
'None -> 'None
}
}
```
then you can do:
```
type Token = 'Public Unit | 'Private Unit | 'Err Unit;
def example(li: List[Char]) -> {t:Token,rem:List[Char]} {
match li {
"public" ++ rem -> {t: 'Public Unit, rem:rem}
"private" ++ rem -> {t: 'Private Unit, rem:rem}
_ -> {t: 'Err Unit, rem: li}
}
}
```
## pattern 1: labelled arguments
```
def [t] List.remove_prefix(prefix: List[t], list: 'from List[t])
```