Convert while/until/times combinators to recursive style #51

Closed
opened 2026-01-18 13:11:47 +00:00 by navicore · 1 comment
navicore commented 2026-01-18 13:11:47 +00:00 (Migrated from github.com)

Background

The Seq language currently has while, until, and times combinators that require neutral stack effects. This creates false expectations for users who expect these to work like loops in other languages - you can't accumulate results on the stack or exit based on runtime criteria.

Problem

  • Neutral stack effect requirement is non-obvious and limiting
  • Creates false expectations based on familiar naming
  • Better to be explicit about stack effects through recursion

Proposal

  1. Audit seq-lisp codebase for uses of while, until, times
  2. Convert each use to recursive style
  3. Document patterns that emerge
  4. Use this experience to decide:
    • Just remove the combinators from Seq, OR
    • Remove AND add new combinators with more honest semantics

Goal

Gather real data on what patterns emerge when forced to use recursion. This will inform whether/how to add iteration combinators back to Seq with correct semantics.

This is part of Seq language design cleanup - making changes before external users depend on current behavior.

## Background The Seq language currently has `while`, `until`, and `times` combinators that require neutral stack effects. This creates false expectations for users who expect these to work like loops in other languages - you can't accumulate results on the stack or exit based on runtime criteria. ## Problem - Neutral stack effect requirement is non-obvious and limiting - Creates false expectations based on familiar naming - Better to be explicit about stack effects through recursion ## Proposal 1. Audit seq-lisp codebase for uses of `while`, `until`, `times` 2. Convert each use to recursive style 3. Document patterns that emerge 4. Use this experience to decide: - Just remove the combinators from Seq, OR - Remove AND add new combinators with more honest semantics ## Goal Gather real data on what patterns emerge when forced to use recursion. This will inform whether/how to add iteration combinators back to Seq with correct semantics. ## Related This is part of Seq language design cleanup - making changes before external users depend on current behavior.
navicore commented 2026-01-18 22:16:03 +00:00 (Migrated from github.com)

❯ can you point me to an example of the -loop pattern?

⏺ Read(src/eval.seq)
⎿  Read 20 lines

⏺ Here's a simple one - list-length at src/eval.seq:250-258:

: list-length ( SexprList -- Int )
0 swap list-length-loop ; # Setup: put accumulator (0) under the list

: list-length-loop ( Int SexprList -- Int )
dup snil? if
drop # Empty list? Drop it, return accumulator
else
scdr swap 1 i.add swap # Get rest, increment acc, swap back
list-length-loop # Tail recurse
then ;

Here's one that builds a result - append-loop at src/eval.seq:3008-3018:

⏺ Read(src/eval.seq)
⎿  Read 20 lines

⏺ : append-lists ( SexprList SexprList -- SexprList )
swap list-reverse swap append-loop ;

: append-loop ( SexprList SexprList -- SexprList )
over snil? if
nip # List1 empty - return List2
else
over scar swap scons # Prepend car of List1 to List2
swap scdr swap # Move to rest of List1
append-loop # Tail recurse
then ;

❯ can you point me to an example of the -loop pattern? ⏺ Read(src/eval.seq) ⎿  Read 20 lines ⏺ Here's a simple one - list-length at src/eval.seq:250-258: : list-length ( SexprList -- Int ) 0 swap list-length-loop ; # Setup: put accumulator (0) under the list : list-length-loop ( Int SexprList -- Int ) dup snil? if drop # Empty list? Drop it, return accumulator else scdr swap 1 i.add swap # Get rest, increment acc, swap back list-length-loop # Tail recurse then ; Here's one that builds a result - append-loop at src/eval.seq:3008-3018: ⏺ Read(src/eval.seq) ⎿  Read 20 lines ⏺ : append-lists ( SexprList SexprList -- SexprList ) swap list-reverse swap append-loop ; : append-loop ( SexprList SexprList -- SexprList ) over snil? if nip # List1 empty - return List2 else over scar swap scons # Prepend car of List1 to List2 swap scdr swap # Move to rest of List1 append-loop # Tail recurse then ;
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
navicore/seq-lisp#51
No description provided.