ee5807d73c
Adds the two canonical prefix-slicing combinators to std_list.
First fns in std_list to combine `if` + Int arithmetic + recursive
ADT pattern in one body.
take : forall a. (Int, List<a>) -> List<a>
— first n elements (or all of xs if shorter than n).
drop : forall a. (Int, List<a>) -> List<a>
— list with first n elements removed (Nil if n >= length).
Both use `(if (<= n 0) ...)` as the base-case guard since
literal sub-patterns inside Ctor patterns aren't yet supported
(queued as 16c — would let take/drop collapse the if into the
match).
examples/std_list_more_demo: builds [1, 2, 3, 4, 5] once and
exercises take/drop at n=0, n=mid, n=overflow on each. Expected
output 0, 3, 5, 5, 3, 0 (one per line).
Tests: 95/95 (e2e went from 35 to 36). std_list grew from 10 to
12 combinators; total stdlib 5 modules / 29 combinators. No new
compiler bug surfaced.
Pre-existing std_list defs are byte-identical (verified via diff
on .ailx and round-trip on .ail.json), so the five downstream
importers (std_list_demo, std_list_stress, std_either_list,
std_either_list_demo, list_map_poly) need no regeneration.
197 lines
5.7 KiB
Plaintext
197 lines
5.7 KiB
Plaintext
; Iter 15b — second stdlib module: polymorphic singly-linked lists.
|
|
; Imports std_maybe so head/tail can return Maybe<a> / Maybe<List<a>>.
|
|
; All cross-module references use the qualified form per the Iter 14h
|
|
; convention: `std_maybe.Maybe` at type-name slots, `std_maybe.from_maybe`
|
|
; for fns. Bare ctor names (`Just`, `Nothing`) stay unqualified — once
|
|
; the type is resolved the ctor lookup is unambiguous.
|
|
|
|
(module std_list
|
|
|
|
(import std_maybe)
|
|
|
|
(data List (vars a)
|
|
(doc "Polymorphic singly-linked list: Nil or Cons<a, List<a>>.")
|
|
(ctor Nil)
|
|
(ctor Cons a (con List a)))
|
|
|
|
(fn fold_left
|
|
(doc "Tail-recursive left fold. The recursive call is in tail position and is marked.")
|
|
(type
|
|
(forall (vars a b)
|
|
(fn-type
|
|
(params (fn-type (params b a) (ret b))
|
|
b
|
|
(con List a))
|
|
(ret b))))
|
|
(params f acc xs)
|
|
(body
|
|
(match xs
|
|
(case (pat-ctor Nil) acc)
|
|
(case (pat-ctor Cons h t)
|
|
(tail-app fold_left f (app f acc h) t)))))
|
|
|
|
(fn fold_right
|
|
(doc "Right fold. Constructor-blocked: the recursive call is the second arg of f, NOT a tail position.")
|
|
(type
|
|
(forall (vars a b)
|
|
(fn-type
|
|
(params (fn-type (params a b) (ret b))
|
|
b
|
|
(con List a))
|
|
(ret b))))
|
|
(params f acc xs)
|
|
(body
|
|
(match xs
|
|
(case (pat-ctor Nil) acc)
|
|
(case (pat-ctor Cons h t)
|
|
(app f h (app fold_right f acc t))))))
|
|
|
|
(fn length
|
|
(doc "Length via fold_left. The accumulating lambda ignores the element and increments the counter.")
|
|
(type
|
|
(forall (vars a)
|
|
(fn-type
|
|
(params (con List a))
|
|
(ret (con Int)))))
|
|
(params xs)
|
|
(body
|
|
(app fold_left
|
|
(lam (params (typed c (con Int)) (typed _ a))
|
|
(ret (con Int))
|
|
(body (app + c 1)))
|
|
0
|
|
xs)))
|
|
|
|
(fn reverse
|
|
(doc "Reverse via fold_left with a flipping accumulator. Tail-recursive by virtue of the fold_left call.")
|
|
(type
|
|
(forall (vars a)
|
|
(fn-type
|
|
(params (con List a))
|
|
(ret (con List a)))))
|
|
(params xs)
|
|
(body
|
|
(app fold_left
|
|
(lam (params (typed acc (con List a)) (typed h a))
|
|
(ret (con List a))
|
|
(body (term-ctor List Cons h acc)))
|
|
(term-ctor List Nil)
|
|
xs)))
|
|
|
|
(fn is_empty
|
|
(doc "True iff the list is Nil.")
|
|
(type
|
|
(forall (vars a)
|
|
(fn-type
|
|
(params (con List a))
|
|
(ret (con Bool)))))
|
|
(params xs)
|
|
(body
|
|
(match xs
|
|
(case (pat-ctor Nil) true)
|
|
(case (pat-ctor Cons _ _) false))))
|
|
|
|
(fn head
|
|
(doc "Returns Just<a> of the first element, or Nothing for an empty list. Cross-module Maybe.")
|
|
(type
|
|
(forall (vars a)
|
|
(fn-type
|
|
(params (con List a))
|
|
(ret (con std_maybe.Maybe a)))))
|
|
(params xs)
|
|
(body
|
|
(match xs
|
|
(case (pat-ctor Nil) (term-ctor std_maybe.Maybe Nothing))
|
|
(case (pat-ctor Cons h _) (term-ctor std_maybe.Maybe Just h)))))
|
|
|
|
(fn tail
|
|
(doc "Returns Just<List<a>> of the tail, or Nothing for an empty list.")
|
|
(type
|
|
(forall (vars a)
|
|
(fn-type
|
|
(params (con List a))
|
|
(ret (con std_maybe.Maybe (con List a))))))
|
|
(params xs)
|
|
(body
|
|
(match xs
|
|
(case (pat-ctor Nil) (term-ctor std_maybe.Maybe Nothing))
|
|
(case (pat-ctor Cons _ t) (term-ctor std_maybe.Maybe Just t)))))
|
|
|
|
(fn append
|
|
(doc "Concatenate two lists. Constructor-blocked recursion: the recursive call is inside Cons, NOT a tail.")
|
|
(type
|
|
(forall (vars a)
|
|
(fn-type
|
|
(params (con List a) (con List a))
|
|
(ret (con List a)))))
|
|
(params xs ys)
|
|
(body
|
|
(match xs
|
|
(case (pat-ctor Nil) ys)
|
|
(case (pat-ctor Cons h t)
|
|
(term-ctor List Cons h (app append t ys))))))
|
|
|
|
(fn map
|
|
(doc "Polymorphic map. Constructor-blocked recursion.")
|
|
(type
|
|
(forall (vars a b)
|
|
(fn-type
|
|
(params (fn-type (params a) (ret b))
|
|
(con List a))
|
|
(ret (con List b)))))
|
|
(params f xs)
|
|
(body
|
|
(match xs
|
|
(case (pat-ctor Nil) (term-ctor List Nil))
|
|
(case (pat-ctor Cons h t)
|
|
(term-ctor List Cons (app f h) (app map f t))))))
|
|
|
|
(fn filter
|
|
(doc "Keep elements where p is true. Constructor-blocked when p holds; non-tail recursive call when p is false.")
|
|
(type
|
|
(forall (vars a)
|
|
(fn-type
|
|
(params (fn-type (params a) (ret (con Bool)))
|
|
(con List a))
|
|
(ret (con List a)))))
|
|
(params p xs)
|
|
(body
|
|
(match xs
|
|
(case (pat-ctor Nil) (term-ctor List Nil))
|
|
(case (pat-ctor Cons h t)
|
|
(if (app p h)
|
|
(term-ctor List Cons h (app filter p t))
|
|
(app filter p t))))))
|
|
|
|
(fn take
|
|
(doc "First n elements of xs (or all of xs if it has fewer than n).")
|
|
(type
|
|
(forall (vars a)
|
|
(fn-type
|
|
(params (con Int) (con List a))
|
|
(ret (con List a)))))
|
|
(params n xs)
|
|
(body
|
|
(if (app <= n 0)
|
|
(term-ctor List Nil)
|
|
(match xs
|
|
(case (pat-ctor Nil) (term-ctor List Nil))
|
|
(case (pat-ctor Cons h t)
|
|
(term-ctor List Cons h (app take (app - n 1) t)))))))
|
|
|
|
(fn drop
|
|
(doc "All elements of xs after the first n (or Nil if xs has fewer than n elements).")
|
|
(type
|
|
(forall (vars a)
|
|
(fn-type
|
|
(params (con Int) (con List a))
|
|
(ret (con List a)))))
|
|
(params n xs)
|
|
(body
|
|
(if (app <= n 0)
|
|
xs
|
|
(match xs
|
|
(case (pat-ctor Nil) (term-ctor List Nil))
|
|
(case (pat-ctor Cons _ t)
|
|
(app drop (app - n 1) t)))))))
|