feat(lang): L5 generic records and functions
property Pool<T> { ... }, function first<T>(xs: []T) -> T, map<T, U> over fn
types; a type writes an instance as Pool<Thing>, nested as deep as needed. The
parser names an instance Pool$Thing and remembers its generic and arguments; the
checker takes the generic declarations out, infers a call's type arguments from
its arguments or its result's declared slot, and makes each instance once as an
ordinary record or function, checked like any other. Errors print Pool<Thing>.
An instance keeps its generic's module and export (L3). ludic-fmt keeps type
arguments together while spacing comparisons and shifts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
57b66bdf47
commit
6a24b14f0e
26 changed files with 61796 additions and 51949 deletions
8
examples/rejected/generic_arity.ludic
Normal file
8
examples/rejected/generic_arity.ludic
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# L5: a generic takes as many type arguments as it has parameters
|
||||
program GenericArity {
|
||||
property Pool<T> { n: int = 0 }
|
||||
entry {
|
||||
let p = new Pool<int, string>
|
||||
print(p.n)
|
||||
}
|
||||
}
|
||||
9
examples/rejected/generic_mismatch.ludic
Normal file
9
examples/rejected/generic_mismatch.ludic
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# L5: two instances of one generic are two types
|
||||
program GenericMismatch {
|
||||
property Pool<T> { n: int = 0 }
|
||||
entry {
|
||||
let ints = new Pool<int>
|
||||
let words: Pool<string> = ints
|
||||
print(words.n)
|
||||
}
|
||||
}
|
||||
9
examples/rejected/generic_unbound.ludic
Normal file
9
examples/rejected/generic_unbound.ludic
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# L5: a call whose type arguments nothing decides is refused - give the result a declared type
|
||||
program GenericUnbound {
|
||||
property Pool<T> { n: int = 0 }
|
||||
function pool_new<T>() -> Pool<T> { return new Pool<T> }
|
||||
entry {
|
||||
let p = pool_new()
|
||||
print(p.n)
|
||||
}
|
||||
}
|
||||
9
examples/rejected/private_generic.ludic
Normal file
9
examples/rejected/private_generic.ludic
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# L5 + L3: an instance keeps its generic's module and export - a private generic stays private
|
||||
import "private_kit"
|
||||
program PrivateGeneric {
|
||||
entry {
|
||||
let p = new Pool<int>
|
||||
grow(p)
|
||||
print(pool_len(p))
|
||||
}
|
||||
}
|
||||
2
examples/rejected/private_kit/index.ludic
Normal file
2
examples/rejected/private_kit/index.ludic
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
module kit
|
||||
import "pool.ludic"
|
||||
11
examples/rejected/private_kit/pool.ludic
Normal file
11
examples/rejected/private_kit/pool.ludic
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
export property Pool<T> {
|
||||
items: []T = null
|
||||
}
|
||||
function grow<T>(p: Pool<T>) -> void {
|
||||
if p.items == null { p.items = new []T }
|
||||
}
|
||||
export function pool_add<T>(p: Pool<T>, x: T) -> void {
|
||||
grow(p)
|
||||
push(p.items, x)
|
||||
}
|
||||
export function pool_len<T>(p: Pool<T>) -> int { return len(p.items) }
|
||||
Loading…
Add table
Add a link
Reference in a new issue