Iter 15h — std_list extension: take, drop
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.
This commit is contained in:
@@ -3042,3 +3042,77 @@ not change observable behaviour for any prior fixture.
|
||||
**Queue update.** 15g-aux done. Unchanged: 16b (local recursive
|
||||
let), 16c (Lit-in-Ctor patterns), 17a (per-fn arena, gated on
|
||||
user discussion of memory management).
|
||||
|
||||
---
|
||||
|
||||
## Iter 15h — std_list extension: take, drop
|
||||
|
||||
**Goal.** Extend `std_list` with the two index-driven prefix
|
||||
combinators `take` and `drop`. They are the first `std_list` fns to
|
||||
combine `if` + Int arithmetic + recursive ADT pattern in a single
|
||||
body — every previous `std_list` fn was either a fold/HOF
|
||||
(fold_left, fold_right, length, map, filter, reverse) or a pure
|
||||
match-on-Cons (head, tail, append, is_empty). 15h closes the
|
||||
canonical-prefix-slicing gap and dogfoods the `if (<= n 0)` +
|
||||
`(- n 1)` interaction inside a recursive Cons-pattern body.
|
||||
|
||||
**What shipped.**
|
||||
|
||||
- `examples/std_list.ailx` — `take` and `drop` appended after
|
||||
`filter`. All ten pre-existing defs byte-identical (verified via
|
||||
`cargo run -p ail -- check` on every downstream importer:
|
||||
`std_list_demo`, `std_list_stress`, `std_either_list`,
|
||||
`std_either_list_demo`, `list_map_poly`). Both new fns are
|
||||
`forall (vars a). (Int, List<a>) -> List<a>`. `take` is
|
||||
constructor-blocked recursive (`Cons h (take (n-1) t)`); `drop`
|
||||
is direct recursive (the recursive call is the arm body, no
|
||||
Cons wrap), so the `match` arm is in tail position relative to
|
||||
the `if`'s `else` branch — but neither call site is marked
|
||||
`tail-app` because the surrounding `if` is not the fn's
|
||||
immediate body. Conservative; matches the rest of `std_list`'s
|
||||
marking discipline.
|
||||
- `examples/std_list_more_demo.ailx` — six prints exercising both
|
||||
combinators at all three boundary regimes (n=0, 0<n<length,
|
||||
n>length). Reuses `std_list_demo`'s `(const xs)` idiom for the
|
||||
canonical `[1, 2, 3, 4, 5]`. Output: `0 / 3 / 5 / 5 / 3 / 0`.
|
||||
- `crates/ail/tests/e2e.rs::std_list_more_demo` (e2e count
|
||||
35 → 36).
|
||||
|
||||
**`(if (<= n 0) ...)` as the base-case guard.** Both fns gate the
|
||||
recursion on the int counter at the top of the body, _outside_ the
|
||||
match. The dual-arm `(case (pat-ctor Cons h t) ...)` then handles
|
||||
only the n>0 path — so the n=0 branch never re-enters the match,
|
||||
and the recursive call is reached only when the list is non-empty
|
||||
and n is still positive. This is a deliberate workaround for the
|
||||
absence of literal sub-patterns inside Ctor patterns: a
|
||||
hypothetical `(case (pat-ctor Cons _ _) (case-when (== n 0) ...))`
|
||||
or matching `n` against `0` directly is queued as 16c. With 16c
|
||||
landed, both fns could collapse the `if` into the match.
|
||||
|
||||
**No new compiler bug surfaced.** The `if` + Int-arithmetic +
|
||||
recursive ADT pattern shape is the first instance for `std_list`
|
||||
in particular but not new for the compiler — `gc_stress` and
|
||||
`std_list_stress` already exercised `(if (== n 0) ...)` with
|
||||
`(- n 1)` recursion at the top level. `<=` on `Int` and the
|
||||
forall-`a` instantiation through the `match` cleanly reused the
|
||||
same monomorphisation paths. Round-trip `render | parse` stays
|
||||
canonical for both new files.
|
||||
|
||||
**Tests: 95/95.**
|
||||
|
||||
- e2e: 36 (was 35, +1 for `std_list_more_demo`).
|
||||
- All other crates unchanged.
|
||||
|
||||
**Cumulative state, post-15h.**
|
||||
|
||||
- Stdlib: 5 modules (`std_maybe`, `std_list`, `std_either`,
|
||||
`std_pair`, `std_either_list`); **29** combinators total
|
||||
(27 + 2). All four primary `std_list` operations — length, map,
|
||||
filter, take/drop — are now present, plus the head/tail/append/
|
||||
reverse/is_empty/fold_left/fold_right surface from 15b.
|
||||
- Compiler bugs surfaced and fixed in dogfood since 14a: 5/5
|
||||
(unchanged from 15g-aux).
|
||||
|
||||
**Queue update.** 15h done. Remaining: 16b (local recursive let),
|
||||
16c (Lit-in-Ctor patterns — would simplify `take`/`drop`), 17a
|
||||
(per-fn arena, gated on user discussion).
|
||||
|
||||
Reference in New Issue
Block a user