load "nat.quox"; load "maybe.quox"; load "bool.quox"; namespace vec { def0 Vec : ℕ → ★ → ★ = λ n A ⇒ caseω n return ★ of { zero ⇒ {nil}; succ _, 0.Tail ⇒ A × Tail }; def elim : 0.(A : ★) → 0.(P : (n : ℕ) → Vec n A → ★) → P 0 'nil → ω.((x : A) → 0.(n : ℕ) → 0.(xs : Vec n A) → P n xs → P (succ n) (x, xs)) → (n : ℕ) → (xs : Vec n A) → P n xs = λ A P pn pc n ⇒ case n return n' ⇒ (xs' : Vec n' A) → P n' xs' of { zero ⇒ λ nil ⇒ case nil return nil' ⇒ P 0 nil' of { 'nil ⇒ pn }; succ n, ih ⇒ λ cons ⇒ case cons return cons' ⇒ P (succ n) cons' of { (first, rest) ⇒ pc first n rest (ih rest) } }; -- haha gross def elimω : 0.(A : ★) → 0.(P : (n : ℕ) → Vec n A → ★) → ω.(P 0 'nil) → ω.(ω.(x : A) → 0.(n : ℕ) → 0.(xs : Vec n A) → ω.(P n xs) → P (succ n) (x, xs)) → ω.(n : ℕ) → ω.(xs : Vec n A) → P n xs = λ A P pn pc n ⇒ caseω n return n' ⇒ ω.(xs' : Vec n' A) → P n' xs' of { zero ⇒ λ nil ⇒ caseω nil return nil' ⇒ P 0 nil' of { 'nil ⇒ pn }; succ n, ω.ih ⇒ λ cons ⇒ caseω cons return cons' ⇒ P (succ n) cons' of { (first, rest) ⇒ pc first n rest (ih rest) } }; #[compile-scheme "(lambda% (n xs) xs)"] def up : 0.(A : ★) → (n : ℕ) → Vec n A → Vec¹ n A = λ A n ⇒ case n return n' ⇒ Vec n' A → Vec¹ n' A of { zero ⇒ λ xs ⇒ case xs return Vec¹ 0 A of { 'nil ⇒ 'nil }; succ n', f' ⇒ λ xs ⇒ case xs return Vec¹ (succ n') A of { (first, rest) ⇒ (first, f' rest) } } } def0 Vec = vec.Vec; namespace list { def0 List : ★ → ★ = λ A ⇒ (len : ℕ) × Vec len A; def Nil : 0.(A : ★) → List A = λ A ⇒ (0, 'nil); def Cons : 0.(A : ★) → A → List A → List A = λ A x xs ⇒ case xs return List A of { (len, elems) ⇒ (succ len, x, elems) }; def elim : 0.(A : ★) → 0.(P : List A → ★) → P (Nil A) → ω.((x : A) → 0.(xs : List A) → P xs → P (Cons A x xs)) → (xs : List A) → P xs = λ A P pn pc xs ⇒ case xs return xs' ⇒ P xs' of { (len, elems) ⇒ vec.elim A (λ n xs ⇒ P (n, xs)) pn (λ x n xs ih ⇒ pc x (n, xs) ih) len elems }; def elimω : 0.(A : ★) → 0.(P : List A → ★) → ω.(P (Nil A)) → ω.(ω.(x : A) → 0.(xs : List A) → ω.(P xs) → P (Cons A x xs)) → ω.(xs : List A) → P xs = λ A P pn pc xs ⇒ caseω xs return xs' ⇒ P xs' of { (len, elems) ⇒ vec.elimω A (λ n xs ⇒ P (n, xs)) pn (λ x n xs ih ⇒ pc x (n, xs) ih) len elems }; -- [fixme] List A <: List¹ A should be automatic, imo #[compile-scheme "(lambda (xs) xs)"] def up : 0.(A : ★) → List A → List¹ A = λ A xs ⇒ case xs return List¹ A of { (len, elems) ⇒ case nat.dup! len return List¹ A of { [p] ⇒ caseω p return List¹ A of { (lenω, eq0) ⇒ case eq0 return List¹ A of { [eq] ⇒ (lenω, vec.up A lenω (coe (𝑖 ⇒ Vec (eq @𝑖) A) @1 @0 elems)) } } } }; def foldr : 0.(A B : ★) → B → ω.(A → B → B) → List A → B = λ A B z f xs ⇒ elim A (λ _ ⇒ B) z (λ x _ y ⇒ f x y) xs; def foldl : 0.(A B : ★) → B → ω.(B → A → B) → List A → B = λ A B z f xs ⇒ foldr A (B → B) (λ b ⇒ b) (λ a g b ⇒ g (f b a)) xs z; def map : 0.(A B : ★) → ω.(A → B) → List A → List B = λ A B f ⇒ foldr A (List B) (Nil B) (λ x ys ⇒ Cons B (f x) ys); -- ugh def foldrω : 0.(A B : ★) → ω.B → ω.(ω.A → ω.B → B) → ω.(List A) → B = λ A B z f xs ⇒ elimω A (λ _ ⇒ B) z (λ x _ y ⇒ f x y) xs; def foldlω : 0.(A B : ★) → ω.B → ω.(ω.B → ω.A → B) → ω.(List A) → B = λ A B z f xs ⇒ foldrω A (ω.B → B) (λ b ⇒ b) (λ a g b ⇒ g (f b a)) xs z; def mapω : 0.(A B : ★) → ω.(ω.A → B) → ω.(List A) → List B = λ A B f ⇒ foldrω A (List B) (Nil B) (λ x ys ⇒ Cons B (f x) ys); def0 All : (A : ★) → (P : A → ★) → List A → ★ = λ A P xs ⇒ foldr¹ A ★ True (λ x ps ⇒ P x × ps) (up A xs); def append : 0.(A : ★) → List A → List A → List A = λ A xs ys ⇒ foldr A (List A) ys (Cons A) xs; def reverse : 0.(A : ★) → List A → List A = λ A ⇒ foldl A (List A) (Nil A) (λ xs x ⇒ Cons A x xs); def find : 0.(A : ★) → ω.(ω.A → Bool) → ω.(List A) → Maybe A = λ A p ⇒ foldlω A (Maybe A) (Nothing A) (λ m x ⇒ maybe.or A m (maybe.check A p x)); postulate0 SchemeList : ★ → ★ #[compile-scheme "(lambda (list) (cons (length list) (fold-right cons 'nil list)))"] postulate from-scheme : 0.(A : ★) → SchemeList A → List A #[compile-scheme "(lambda (list) (let loop [(acc '()) (list (cdr list))] (if (pair? list) (loop (cons (car list) acc) (cdr list)) (reverse acc))))"] postulate to-scheme : 0.(A : ★) → List A → SchemeList A } def0 List = list.List;