# Pair
# ----
def Pair(A, B):
Sigma<&1, &1, A, _ => B>
def Exists(-A: Type, -B: @-x: A -> Type) -> Type:
Sigma<&1, &1, A, B>
def Or(-A: Type, -B: Type) -> Type:
Either<&1, &1, A, B>
def Pair.fst(-A: Type, -B: Type, p: A & B) -> A:
(a, b) = p
a
def Pair.snd(-A: Type, -B: Type, p: A & B) -> B:
(a, b) = p
b
# Effects
# -------
def IO(A):
@-R: Type ->
@k: (A -> IO.OP }
law Word.add_comm.go:
for n: Nat
for a: Word(n)
for b: Word(n)
for c: Bool
{Word.adc(n, a, b, False{}, c) == Word.adc(n, b, a, False{}, c) : Word(n)}
def Word.add_comm.arm(p, h, at, bt, k):
Equal.cong(Word(p), Word(1n+p), w => WCon{h, w},
Word.adc(p, at, bt, False{}, k), Word.adc(p, bt, at, False{}, k),
Word.add_comm.go(p, at, bt, k))
def Word.add_comm.go(n, a, b, c):
match n:
case 0n:
match a b:
case WNil{} WNil{}:
{==}
case 1n+p:
match a b c:
case WCon{False{}, at} WCon{False{}, bt} False{}:
Word.add_comm.arm(p, False{}, at, bt, False{})
case WCon{False{}, at} WCon{False{}, bt} True{}:
Word.add_comm.arm(p, True{}, at, bt, False{})
case WCon{False{}, at} WCon{True{}, bt} False{}:
Word.add_comm.arm(p, True{}, at, bt, False{})
case WCon{False{}, at} WCon{True{}, bt} True{}:
Word.add_comm.arm(p, False{}, at, bt, True{})
case WCon{True{}, at} WCon{False{}, bt} False{}:
Word.add_comm.arm(p, True{}, at, bt, False{})
case WCon{True{}, at} WCon{False{}, bt} True{}:
Word.add_comm.arm(p, False{}, at, bt, True{})
case WCon{True{}, at} WCon{True{}, bt} False{}:
Word.add_comm.arm(p, False{}, at, bt, True{})
case WCon{True{}, at} WCon{True{}, bt} True{}:
Word.add_comm.arm(p, True{}, at, bt, True{})
law Word.add_comm:
for n: Nat
for a: Word(n)
for b: Word(n)
{Word.add(n, a, b) == Word.add(n, b, a) : Word(n)}
def Word.add_comm(n, a, b):
Word.add_comm.go(n, a, b, False{})
def Word.to_nat(n: Nat, w: Word(n)) -> Nat:
match n:
case 0n:
0n
case 1n+p:
match w:
case WCon{False{}, t}:
Nat.double(Word.to_nat(p, t))
case WCon{True{}, t}:
1n+Nat.double(Word.to_nat(p, t))
def Word.mul.go(+n: Nat, m: Nat, a: Word(m), +b: Word(n), acc: Word(n)) ->
Word(n):
match m:
case 0n:
acc
case 1n+mp:
match a:
case WCon{False{}, at}:
Word.mul.go(n, mp, at, Word.shl(n, b), acc)
case WCon{True{}, at}:
Word.mul.go(n, mp, at, Word.shl(n, b), Word.add(n, acc, b))
def Word.mul(+n: Nat, a: Word(n), b: Word(n)) -> Word(n):
Word.mul.go(n, n, a, b, Word.zero(n))
# U32
# ---
def U32.inc(a: U32) -> U32:
match a:
case U32{x}:
U32{Word.inc(32n, x)}
def U32.add(a: U32, b: U32) -> U32:
match a b:
case U32{x} U32{y}:
U32{Word.add(32n, x, y)}
law U32.add_comm:
for a: U32
for b: U32
{U32.add(a, b) == U32.add(b, a) : U32}
def U32.add_comm(a, b):
match a b:
case U32{x} U32{y}:
Equal.cong(Word(32n), U32, w => U32{w}, Word.add(32n, x, y),
Word.add(32n, y, x), Word.add_comm(32n, x, y))
def U32.sub(a: U32, b: U32) -> U32:
match a b:
case U32{x} U32{y}:
U32{Word.sub(32n, x, y)}
def U32.mul(a: U32, b: U32) -> U32:
match a b:
case U32{x} U32{y}:
U32{Word.mul(32n, x, y)}
def U32.not(a: U32) -> U32:
match a:
case U32{x}:
U32{Word.not(32n, x)}
def U32.and(a: U32, b: U32) -> U32:
match a b:
case U32{x} U32{y}:
U32{Word.and(32n, x, y)}
def U32.or(a: U32, b: U32) -> U32:
match a b:
case U32{x} U32{y}:
U32{Word.or(32n, x, y)}
def U32.xor(a: U32, b: U32) -> U32:
match a b:
case U32{x} U32{y}:
U32{Word.xor(32n, x, y)}
def U32.shl(a: U32) -> U32:
match a:
case U32{x}:
U32{Word.shl(32n, x)}
def U32.shr(a: U32) -> U32:
match a:
case U32{x}:
U32{Word.shr(32n, x)}
def U32.shln(a: U32, n: Nat) -> U32:
match n:
case 0n:
a
case 1n+p:
U32.shl(U32.shln(a, p))
def U32.shrn(a: U32, n: Nat) -> U32:
match n:
case 0n:
a
case 1n+p:
U32.shr(U32.shrn(a, p))
def U32.cmp(a: U32, b: U32) -> Cmp:
match a b:
case U32{x} U32{y}:
Word.cmp(32n, x, y)
def U32.is_eq(a: U32, b: U32) -> Bool:
Cmp.is_eq(U32.cmp(a, b))
def U32.is_ne(a: U32, b: U32) -> Bool:
Bool.not(Cmp.is_eq(U32.cmp(a, b)))
def U32.is_lt(a: U32, b: U32) -> Bool:
Cmp.is_lt(U32.cmp(a, b))
def U32.is_le(a: U32, b: U32) -> Bool:
Cmp.is_le(U32.cmp(a, b))
def U32.is_gt(a: U32, b: U32) -> Bool:
Cmp.is_gt(U32.cmp(a, b))
def U32.is_ge(a: U32, b: U32) -> Bool:
Cmp.is_ge(U32.cmp(a, b))
def U32.is_zero(a: U32) -> Bool:
U32.is_eq(a, 0)
def U32.to_nat(a: U32) -> Nat:
match a:
case U32{w}:
Word.to_nat(32n, w)
def U32.from_nat(n: Nat) -> U32:
match n:
case 0n:
0
case 1n+p:
U32.inc(U32.from_nat(p))
def U32.divmod.go.fin(-p: Nat, q: Word(p), s: U32, b: U32, g: Bool) ->
Word(1n+p) & U32:
match g:
case True{}:
(WCon{True{}, q}, U32.sub(s, b))
case False{}:
(WCon{False{}, q}, s)
def U32.divmod.go.shl(-p: Nat, q: Word(p), +b: U32, ts: Bool & Word(32n)) ->
Word(1n+p) & U32:
(t, s) = ts
+s2 = {U32{s} : U32}
U32.divmod.go.fin(p, q, s2, b, Bool.or(t, U32.is_ge(s2, b)))
def U32.divmod.go.rec(-p: Nat, a0: Bool, +b: U32, qr: Word(p) & U32) ->
Word(1n+p) & U32:
(q, r) = qr
U32{rw} = r
U32.divmod.go.shl(p, q, b, Word.shl.out(32n, a0, rw))
def U32.divmod.go(m: Nat, a: Word(m), +b: U32) -> Word(m) & U32:
match m a:
case 0n WNil{}:
(WNil{}, 0)
case 1n+p WCon{a0, hi}:
U32.divmod.go.rec(p, a0, b, U32.divmod.go(p, hi, b))
def U32.div.fin(qr: Word(32n) & U32) -> U32:
(q, r) = qr
U32{q}
def U32.div.if(aw: Word(32n), b: U32, z: Bool) -> U32:
match z:
case True{}:
0
case False{}:
U32.div.fin(U32.divmod.go(32n, aw, b))
def U32.div(a: U32, +b: U32) -> U32:
U32{aw} = a
U32.div.if(aw, b, U32.is_zero(b))
def U32.mod.fin(qr: Word(32n) & U32) -> U32:
(q, r) = qr
r
def U32.mod.if(aw: Word(32n), b: U32, z: Bool) -> U32:
match z:
case True{}:
U32{aw}
case False{}:
U32.mod.fin(U32.divmod.go(32n, aw, b))
def U32.mod(a: U32, +b: U32) -> U32:
U32{aw} = a
U32.mod.if(aw, b, U32.is_zero(b))
def U32.min(+a: U32, +b: U32) -> U32:
Bool.pick(U32, U32.is_lt(a, b), a, b)
def U32.max(+a: U32, +b: U32) -> U32:
Bool.pick(U32, U32.is_lt(a, b), b, a)
def U32.clamp(x: U32, lo: U32, hi: U32) -> U32:
U32.min(U32.max(x, lo), hi)
def U32.pow(+a: U32, n: Nat) -> U32:
match n:
case 0n:
1
case 1n+p:
U32.mul(a, U32.pow(a, p))
def U32.is_even(a: U32) -> Bool:
U32.is_zero(U32.and(a, 1))
# F32
# ---
law U32.to_f32:
for a: U32
F32
law F32.to_u32:
for a: F32
U32
law F32.add:
for a: F32
for b: F32
F32
law F32.sub:
for a: F32
for b: F32
F32
law F32.mul:
for a: F32
for b: F32
F32
law F32.div:
for a: F32
for b: F32
F32
law F32.mod:
for a: F32
for b: F32
F32
law F32.pow:
for a: F32
for b: F32
F32
law F32.atan2:
for a: F32
for b: F32
F32
law F32.neg:
for a: F32
F32
law F32.abs:
for a: F32
F32
law F32.sqrt:
for a: F32
F32
law F32.exp:
for a: F32
F32
law F32.log:
for a: F32
F32
law F32.log2:
for a: F32
F32
law F32.log10:
for a: F32
F32
law F32.sin:
for a: F32
F32
law F32.cos:
for a: F32
F32
law F32.tan:
for a: F32
F32
law F32.asin:
for a: F32
F32
law F32.acos:
for a: F32
F32
law F32.atan:
for a: F32
F32
law F32.sinh:
for a: F32
F32
law F32.cosh:
for a: F32
F32
law F32.tanh:
for a: F32
F32
law F32.floor:
for a: F32
F32
law F32.ceil:
for a: F32
F32
law F32.trunc:
for a: F32
F32
law F32.is_eq:
for a: F32
for b: F32
Bool
law F32.is_ne:
for a: F32
for b: F32
Bool
law F32.is_lt:
for a: F32
for b: F32
Bool
law F32.is_le:
for a: F32
for b: F32
Bool
law F32.is_gt:
for a: F32
for b: F32
Bool
law F32.is_ge:
for a: F32
for b: F32
Bool
law F32.show:
for +a: F32
String
law F32.bits:
for a: F32
U32
law F32.read:
for s: String
Maybe<&2, F32>
def F32.min(+a: F32, +b: F32) -> F32:
Bool.pick(F32, F32.is_lt(a, b), a, b)
def F32.max(+a: F32, +b: F32) -> F32:
Bool.pick(F32, F32.is_lt(a, b), b, a)
def F32.clamp(x: F32, lo: F32, hi: F32) -> F32:
F32.min(F32.max(x, lo), hi)
def F32.lerp(+a: F32, b: F32, t: F32) -> F32:
F32.add(a, F32.mul(F32.sub(b, a), t))
def F32.square(+a: F32) -> F32:
F32.mul(a, a)
def F32.hypot(+x: F32, +y: F32) -> F32:
F32.sqrt(F32.add(F32.mul(x, x), F32.mul(y, y)))
def F32.round(a: F32) -> F32:
F32.floor(F32.add(a, 0.5))
def F32.pi() -> F32:
3.14159265
def F32.from_nat(n: Nat) -> F32:
U32.to_f32(U32.from_nat(n))
def F32.to_nat(a: F32) -> Nat:
U32.to_nat(F32.to_u32(a))
# Char
# ----
def Char.cmp(a: Char, b: Char) -> (Char & Char) & Cmp:
match a b:
case Chr{+x} Chr{+y}:
((Chr{x}, Chr{y}), U32.cmp(x, y))
def Char.to_u32(c: Char) -> U32:
match c:
case Chr{x}:
x
def Char.from_u32(x: U32) -> Char:
Chr{x}
def Char.is_eq(a: Char, b: Char) -> Bool:
match a b:
case Chr{x} Chr{y}:
U32.is_eq(x, y)
def Char.is_digit(c: Char) -> Bool:
match c:
case Chr{+x}:
Bool.and(U32.is_ge(x, 48), U32.is_le(x, 57))
def Char.is_upper(c: Char) -> Bool:
match c:
case Chr{+x}:
Bool.and(U32.is_ge(x, 65), U32.is_le(x, 90))
def Char.is_lower(c: Char) -> Bool:
match c:
case Chr{+x}:
Bool.and(U32.is_ge(x, 97), U32.is_le(x, 122))
def Char.is_alpha(+c: Char) -> Bool:
Bool.or(Char.is_upper(c), Char.is_lower(c))
def Char.is_space(c: Char) -> Bool:
match c:
case Chr{+x}:
Bool.or(U32.is_eq(x, 32), Bool.and(U32.is_ge(x, 9), U32.is_le(x, 13)))
def Char.to_upper(+c: Char) -> Char:
Bool.pick(Char, Char.is_lower(c), Chr{U32.sub(Char.to_u32(c), 32)}, c)
def Char.to_lower(+c: Char) -> Char:
Bool.pick(Char, Char.is_upper(c), Chr{U32.add(Char.to_u32(c), 32)}, c)
# String
# ------
def String.append(a: String, b: String) -> String:
match a:
case SNil{}:
b
case SCon{h, t}:
SCon{h, String.append(t, b)}
def String.cmp.rec(h1b: Char, h2b: Char, rr: (String & String) & Cmp) ->
(String & String) & Cmp:
((t1b, t2b), r) = rr
((SCon{h1b, t1b}, SCon{h2b, t2b}), r)
law String.cmp:
for a: String
for b: String
(String & String) & Cmp
def String.cmp.fin(t1: String, t2: String, hc: (Char & Char) & Cmp) ->
(String & String) & Cmp:
((h1b, h2b), c) = hc
match c:
case LT{}:
((SCon{h1b, t1}, SCon{h2b, t2}), LT{})
case EQ{}:
String.cmp.rec(h1b, h2b, String.cmp(t1, t2))
case GT{}:
((SCon{h1b, t1}, SCon{h2b, t2}), GT{})
def String.cmp(a, b):
match a b:
case SNil{} SNil{}:
((SNil{}, SNil{}), EQ{})
case SNil{} SCon{h, t}:
((SNil{}, SCon{h, t}), LT{})
case SCon{h, t} SNil{}:
((SCon{h, t}, SNil{}), GT{})
case SCon{h1, t1} SCon{h2, t2}:
String.cmp.fin(t1, t2, Char.cmp(h1, h2))
def String.eq.fin(r: (String & String) & Cmp) -> Bool:
((a2, b2), c) = r
Cmp.is_eq(c)
def String.eq(a: String, b: String) -> Bool:
String.eq.fin(String.cmp(a, b))
def String.length(s: String) -> Nat:
match s:
case SNil{}:
0n
case SCon{h, t}:
1n+String.length(t)
def String.is_empty(s: String) -> Bool:
match s:
case SNil{}:
True{}
case SCon{h, t}:
False{}
def String.reverse.go(s: String, acc: String) -> String:
match s:
case SNil{}:
acc
case SCon{h, t}:
String.reverse.go(t, SCon{h, acc})
def String.reverse(s: String) -> String:
String.reverse.go(s, SNil{})
def String.order.fin(r: (String & String) & Cmp) -> Cmp:
(ab, c) = r
c
def String.order(a: String, b: String) -> Cmp:
String.order.fin(String.cmp(a, b))
def String.is_lt(a: String, b: String) -> Bool:
Cmp.is_lt(String.order(a, b))
def String.is_le(a: String, b: String) -> Bool:
Cmp.is_le(String.order(a, b))
def String.is_gt(a: String, b: String) -> Bool:
Cmp.is_gt(String.order(a, b))
def String.is_ge(a: String, b: String) -> Bool:
Cmp.is_ge(String.order(a, b))
law String.starts_with:
for s: String
for p: String
Bool
def String.starts_with.if(t: String, pt: String, same: Bool) -> Bool:
match same:
case False{}:
False{}
case True{}:
String.starts_with(t, pt)
def String.starts_with(s, p):
match s p:
case SNil{} SNil{}:
True{}
case SNil{} SCon{h, t}:
False{}
case SCon{h, t} SNil{}:
True{}
case SCon{x, xt} SCon{y, yt}:
String.starts_with.if(xt, yt, Char.is_eq(x, y))
def String.ends_with(s: String, p: String) -> Bool:
String.starts_with(String.reverse(s), String.reverse(p))
law String.contains:
for +s: String
for +p: String
Bool
def String.contains.if(t: String, p: String, here: Bool) -> Bool:
match here:
case False{}:
String.contains(t, p)
case True{}:
True{}
def String.contains(s, p):
match s:
case SNil{}:
String.is_empty(p)
case SCon{h, t}:
String.contains.if(t, p, String.starts_with(SCon{h, t}, p))
def String.take(s: String, n: Nat) -> String:
match s n:
case SNil{} _:
SNil{}
case SCon{h, t} 0n:
SNil{}
case SCon{h, t} 1n+p:
SCon{h, String.take(t, p)}
def String.drop(s: String, n: Nat) -> String:
match s n:
case SNil{} _:
SNil{}
case SCon{h, t} 0n:
SCon{h, t}
case SCon{h, t} 1n+p:
String.drop(t, p)
def String.get(s: String, n: Nat) -> Maybe<&2, Char>:
match s n:
case SNil{} _:
None{}
case SCon{h, t} 0n:
Some{h}
case SCon{h, t} 1n+p:
String.get(t, p)
def String.to_list(s: String) -> List<&2, Char>:
match s:
case SNil{}:
Nil{}
case SCon{h, t}:
h <> String.to_list(t)
def String.from_list(cs: List<&2, Char>) -> String:
match cs:
case Nil{}:
SNil{}
case h <> t:
SCon{h, String.from_list(t)}
def String.concat(xs: List<&2, String>) -> String:
match xs:
case Nil{}:
SNil{}
case h <> t:
String.append(h, String.concat(t))
def String.join.go(xs: List<&2, String>, h: String, +sep: String) -> String:
match xs:
case Nil{}:
h
case h2 <> t:
String.append(h, String.append(sep, String.join.go(t, h2, sep)))
def String.join(xs: List<&2, String>, +sep: String) -> String:
match xs:
case Nil{}:
SNil{}
case h <> t:
String.join.go(t, h, sep)
def String.split.push(c: Char, ps: List<&2, String>) -> List<&2, String>:
match ps:
case Nil{}:
[SCon{c, SNil{}}]
case h <> t:
SCon{c, h} <> t
def String.split.fin(c: Char, r: List<&2, String>, cut: Bool) ->
List<&2, String>:
match cut:
case False{}:
String.split.push(c, r)
case True{}:
SNil{} <> r
def String.split(s: String, +sep: Char) -> List<&2, String>:
match s:
case SNil{}:
[SNil{}]
case SCon{+h, t}:
String.split.fin(h, String.split(t, sep), Char.is_eq(h, sep))
def String.lines(s: String) -> List<&2, String>:
String.split(s, '\n')
def String.repeat(+s: String, n: Nat) -> String:
match n:
case 0n:
SNil{}
case 1n+p:
String.append(s, String.repeat(s, p))
def String.to_upper(s: String) -> String:
match s:
case SNil{}:
SNil{}
case SCon{h, t}:
SCon{Char.to_upper(h), String.to_upper(t)}
def String.to_lower(s: String) -> String:
match s:
case SNil{}:
SNil{}
case SCon{h, t}:
SCon{Char.to_lower(h), String.to_lower(t)}
law String.trim_start:
for s: String
String
def String.trim_start.if(h: Char, t: String, space: Bool) -> String:
match space:
case False{}:
SCon{h, t}
case True{}:
String.trim_start(t)
def String.trim_start(s):
match s:
case SNil{}:
SNil{}
case SCon{+h, t}:
String.trim_start.if(h, t, Char.is_space(h))
def String.trim_end(s: String) -> String:
String.reverse(String.trim_start(String.reverse(s)))
def String.trim(s: String) -> String:
String.trim_end(String.trim_start(s))
# Text
# ----
def Nat.show.put(qr: Nat & Nat) -> Char & Nat:
(q, r) = qr
(Chr{U32.from_nat(Nat.add(48n, r))}, q)
law Nat.show.go:
for f : Nat
for n : Nat
for acc : String
String
def Nat.show.fin(g: Nat, acc: String, dq: Char & Nat) -> String:
(d, q) = dq
match q:
case 0n:
SCon{d, acc}
case 1n+p:
Nat.show.go(g, 1n+p, SCon{d, acc})
def Nat.show.go(f, n, acc):
match f:
case 0n:
acc
case 1n+g:
Nat.show.fin(g, acc, Nat.show.put(Nat.divmod(n, 10n)))
def Nat.show(n: Nat) -> String:
+m = n
Nat.show.fin(m, SNil{}, Nat.show.put(Nat.divmod(m, 10n)))
law Nat.read.go:
for s : String
for +acc : Nat
Maybe<&2, Nat>
def Nat.read.max() -> Nat:
Nat.mul(U32.to_nat(16777215), U32.to_nat(16777217))
def Nat.read.fit(acc: Nat, qr: Nat & Nat) -> Bool:
(q, r) = qr
Bool.not(Nat.is_lt(q, acc))
def Nat.read.if(t: String, acc: Nat, d: U32, ok: Bool) -> Maybe<&2, Nat>:
match ok:
case True{}:
Nat.read.go(t, Nat.add(Nat.mul(acc, 10n), U32.to_nat(d)))
case False{}:
None{}
def Nat.read.go(s, acc):
match s:
case SNil{}:
Some{acc}
case SCon{Chr{x}, t}:
+d = U32.sub(x, 48)
Nat.read.if(t, acc, d, Bool.and(U32.is_lt(d, 10), Nat.read.fit(acc,
Nat.divmod(Nat.sub(Nat.read.max(), U32.to_nat(d)), 10n))))
def Nat.read(s: String) -> Maybe<&2, Nat>:
match s:
case SNil{}:
None{}
case SCon{h, t}:
Nat.read.go(SCon{h, t}, 0n)
law U32.show.go:
for f : Nat
for +n : U32
for acc : String
String
def U32.show.fin(g: Nat, acc: String, +n: U32, z: Bool) -> String:
match z:
case True{}:
acc
case False{}:
U32.show.go(g, U32.div(n, 10),
SCon{Chr{U32.add(48, U32.mod(n, 10))}, acc})
def U32.show.go(f, n, acc):
match f:
case 0n:
acc
case 1n+g:
U32.show.fin(g, acc, n, U32.is_zero(n))
def U32.show.if(a: U32, z: Bool) -> String:
match z:
case True{}:
SCon{Chr{48}, SNil{}}
case False{}:
U32.show.go(10n, a, SNil{})
def U32.show(a: U32) -> String:
+b = a
U32.show.if(b, U32.is_zero(b))
law U32.read.go:
for s : String
for +acc : U32
Maybe<&2, U32>
def U32.read.if(t: String, n: U32, ok: Bool) -> Maybe<&2, U32>:
match ok:
case True{}:
U32.read.go(t, n)
case False{}:
None{}
def U32.read.go(s, acc):
match s:
case SNil{}:
Some{acc}
case SCon{Chr{x}, t}:
+n = U32.add(U32.mul(acc, 10), U32.sub(x, 48))
U32.read.if(t, n, U32.is_eq(U32.div(n, 10), acc))
def U32.read(s: String) -> Maybe<&2, U32>:
match s:
case SNil{}:
None{}
case SCon{h, t}:
U32.read.go(SCon{h, t}, 0)
def Bool.show(b: Bool) -> String:
match b:
case False{}:
"False"
case True{}:
"True"
def Char.show(c: Char) -> String:
SCon{c, SNil{}}
def Maybe.show(~a: Quant, ~A: Kind(a), ~f: A -> String, m: Maybe) ->
String:
match m:
case None{}:
"None"
case Some{x}:
"Some(" ++ f(x) ++ ")"
def List.show.go(~a: Quant, ~A: Kind(a), ~f: A -> String, xs: List) ->
String:
match xs:
case Nil{}:
"]"
case h <> t:
", " ++ f(h) ++ List.show.go(~a, ~A, ~f, t)
def List.show(~a: Quant, ~A: Kind(a), ~f: A -> String, xs: List) ->
String:
match xs:
case Nil{}:
"[]"
case h <> t:
"[" ++ f(h) ++ List.show.go(~a, ~A, ~f, t)
# Array
# -----
def Array.size.node(-T: Type, ys: Array
) -> IO(Unit):
match next:
case None{}:
Window.close(window)
case Some{state}:
rest(window, state)
def App.turn(
-S: Type, shown: Window & Image & List), state: S,
rest: Window -> S -> IO(Unit)
) -> IO(Unit):
(window, image, events) = shown
do IO, Unit, tick(events, state), App.next(S, window, rest))
def App.draw(
-S: Type, window: Window, drawn: S & Image,
tick: List), rest: Window -> S -> IO(Unit)
) -> IO(Unit):
(state, image) = drawn
do IO, window: Window, state: S,
rest: Window -> S -> IO(Unit)
) -> IO(Unit):
App{view, tick} = app
App.draw(S, window, view(state), tick, rest)
def App.loop(~S: Type, ~app: App, fuel: Nat, window: Window, state: S) ->
IO(Unit):
match fuel:
case 0n:
Window.close(window)
case 1n+f:
App.step(S, app, window, state, w => s => App.loop(~S, ~app, f, w, s))
def App.run(
~S: Type, ~app: App, title: String, width: U32, height: U32, state: S
) -> IO(Unit):
do IO), next: Maybe) ->
IO(Maybe):
match next:
case None{}:
IO.pure(Maybe, None{})
case Some{state}:
rest(state)
def App.fold(
-S: Type, app: App, events: List)
) -> IO(Maybe):
App{view, tick} = app
IO.bind(Maybe, Maybe, tick(events, state), App.more(S, rest))
def App.play(~S: Type, ~app: App, frames: List>, state: S) ->
IO(Maybe
):
match frames:
case Nil{}:
IO.pure(Maybe, Some{state})
case events <> rest:
App.fold(S, app, events, state, s => App.play(~S, ~app, rest, s))