Commit2b96acb1Recorded4 Jul 2026Repositorysigil-fp
Re-export threading macros from core
Message
chain.sgl re-exports ->/chain/some-> from (sigil core) instead of defining them locally, following the 2026-07-04 decision to return the threading macros to core. Dual-import (core + fp) verified conflict-free. Rebased onto v0.9.2; the manifest modernization from v0.9.2 is kept as-is (no version bump here).
Changed
README.md | 10 ++++++++++
src/sigil/fp.sgl | 25 ++++++++++++++++---------
src/sigil/fp/chain.sgl | 131 ++++++++++++++++++-----------------------------------------------------------------------------------------------------------------
3 files changed, 44 insertions(+), 122 deletions(-)Diff
README.mdmodified
@@ -91,7 +91,17 @@ Apply multiple functions to the same arguments, returning a list of results:
91
92
Thread values through sequences of expressions, similar to Clojure's threading macros and SRFI-197. 93
+94
> **These macros live in `(sigil core)` now.** `chain`, `->`, and `some->` are+95
> part of core, which is auto-imported into every module, so every program+96
> already has them in scope without importing anything. `(sigil fp chain)`+97
> re-exports them from core purely for backward compatibility, so existing+98
> `(import (sigil fp chain))` / `(import (sigil fp))` code keeps working.+99
100
```scheme+101
;; No import needed — these come from core:+102
(-> 5 (+ 3) (* 2))+103
+104
;; Or, for backward compatibility: 105
(import (sigil fp chain)) 106
``` 107
src/sigil/fp.sglmodified
@@ -1,10 +1,13 @@
1
;;; (sigil fp) - Functional Programming Utilities for Sigil 2
;;;−3
;;; This package provides function composition, partial application,−4
;;; and threading macros for Sigil programs.+3
;;; This package provides function composition and partial application+4
;;; combinators. Import the aggregate module to get everything: 5
;;;−6
;;; Due to Sigil's module system not supporting re-exports, import−7
;;; the specific sub-modules you need:+6
;;; ```scheme+7
;;; (import (sigil fp))+8
;;; ```+9
;;;+10
;;; Or import a specific sub-module: 11
;;; 12
;;; ```scheme 13
;;; ;; Function composition and partial application@@ -12,17 +15,21 @@
15
;;; 16
;;; ;; Threading macros (chain, ->, some->) 17
;;; (import (sigil fp chain))−15
;;;−16
;;; ;; Or import both−17
;;; (import (sigil fp fn)−18
;;; (sigil fp chain)) 18
;;; ``` 19
;;;+20
;;; ## Threading macros live in core+21
;;;+22
;;; The threading macros `chain`, `->`, and `some->` now live in+23
;;; `(sigil core)`, which is auto-imported into every module, so every+24
;;; program already has them in scope without importing anything. The+25
;;; `(sigil fp chain)` sub-module re-exports them from core purely for+26
;;; backward compatibility with existing `(import (sigil fp ...))` code.+27
;;; 28
;;; ## Sub-modules 29
;;; 30
;;; - **(sigil fp fn)** - compose, pipe, partial, partial-right, 31
;;; const, flip, complement, juxt−25
;;; - **(sigil fp chain)** - chain, ->, some->+32
;;; - **(sigil fp chain)** - chain, ->, some-> (re-exported from core) 33
34
(define-library (sigil fp) 35
(import (sigil fp fn)src/sigil/fp/chain.sglmodified
@@ -1,13 +1,24 @@
−1
;;; (sigil fp chain) - Threading Macros+1
;;; (sigil fp chain) - Threading Macros (re-exported from core) 2
;;;−3
;;; Thread values through sequences of expressions, similar to−4
;;; Clojure's threading macros and SRFI-197.+3
;;; The threading macros `chain`, `->`, and `some->` now live in+4
;;; `(sigil core)`, where they were before the 2026-03-31 FP extraction.+5
;;; They are structural control-flow syntax used throughout idiomatic Sigil,+6
;;; not optional combinators, so they belong in core. Since `(sigil core)` is+7
;;; auto-imported into every module, any program already has these macros in+8
;;; scope without importing anything.+9
;;;+10
;;; This module re-exports them so existing `(import (sigil fp chain))` and+11
;;; `(import (sigil fp))` consumers keep working unchanged. Because the+12
;;; re-exported bindings ARE core's bindings (not fresh definitions), a program+13
;;; importing both `(sigil core)` and `(sigil fp)` sees no duplicate-binding+14
;;; conflict.+15
;;;+16
;;; The optional combinators (`compose`, `pipe`, `partial`, `partial-right`,+17
;;; `flip`, `complement`, `juxt`, `const`) remain in `(sigil fp fn)`. 18
;;; 19
;;; ## Basic Threading 20
;;; 21
;;; ```scheme−9
;;; (import (sigil fp chain))−10
;;; 22
;;; ;; Thread-first (no placeholder needed) 23
;;; (chain 5 (+ 3) (* 2)) 24
;;; ; => 16 (same as (* (+ 5 3) 2))@@ -30,111 +41,5 @@
41
;;; ``` 42
43
(define-library (sigil fp chain)−33
(export chain -> some->)−34
−35
(begin−36
−37
;;; Thread a value through a sequence of expressions.−38
;;;−39
;;; Similar to SRFI-197's `chain`. Uses `_` as the placeholder symbol.−40
;;; When a step contains `_`, the threaded value is substituted there.−41
;;; When no `_` is present, the value is inserted as the first argument.−42
;;;−43
;;; ```scheme−44
;;; ;; Thread-first (no placeholder)−45
;;; (chain 5 (+ 3) (* 2))−46
;;; ; => 16 (same as (* (+ 5 3) 2))−47
;;;−48
;;; ;; Explicit placeholder−49
;;; (chain '(1 2 3)−50
;;; (map (lambda (x) (* x 2)) _)−51
;;; (apply + _))−52
;;; ; => 12−53
;;;−54
;;; ;; Placeholder in various positions−55
;;; (chain 10 (- 20 _)) ; => 10 (= 20 - 10)−56
;;; (chain 5 (list 1 2 _ 4)) ; => (1 2 5 4)−57
;;; ```−58
(define-syntax chain−59
(syntax-rules (_ %step)−60
;; Base case: just the value−61
((chain expr)−62
expr)−63
−64
;; Internal: process step result and continue−65
((chain %step result)−66
result)−67
((chain %step result next-step rest ...)−68
(chain result next-step rest ...))−69
−70
;; Step patterns: _ as entire step (identity)−71
((chain expr _ rest ...)−72
(chain %step expr rest ...))−73
−74
;; Step patterns: _ in first position (function position)−75
((chain expr (_ arg ...) rest ...)−76
(chain %step (expr arg ...) rest ...))−77
−78
;; Step patterns: _ in second position (first arg)−79
((chain expr (f _ arg ...) rest ...)−80
(chain %step (f expr arg ...) rest ...))−81
−82
;; Step patterns: _ in third position (second arg)−83
((chain expr (f a _ arg ...) rest ...)−84
(chain %step (f a expr arg ...) rest ...))−85
−86
;; Step patterns: _ in fourth position (third arg)−87
((chain expr (f a b _ arg ...) rest ...)−88
(chain %step (f a b expr arg ...) rest ...))−89
−90
;; Step patterns: _ in fifth position (fourth arg)−91
((chain expr (f a b c _ arg ...) rest ...)−92
(chain %step (f a b c expr arg ...) rest ...))−93
−94
;; Default for lists: no _ found, insert as first arg (thread-first)−95
((chain expr (f arg ...) rest ...)−96
(chain %step (f expr arg ...) rest ...))−97
−98
;; Bare identifier - call with expr as arg (must come last)−99
((chain expr f rest ...)−100
(chain %step (f expr) rest ...))))−101
−102
;;; Alias for `chain` (Clojure-style threading operator).−103
;;;−104
;;; ```scheme−105
;;; (-> 5 (+ 3) (* 2)) ; => 16−106
;;; ```−107
(define-syntax ->−108
(syntax-rules ()−109
((-> . args)−110
(chain . args))))−111
−112
;;; Thread value through steps, short-circuiting on #f.−113
;;;−114
;;; Like `->`, but stops and returns `#f` if any step produces `#f`.−115
;;; Useful for optional/nullable value pipelines.−116
;;;−117
;;; ```scheme−118
;;; ;; Returns #f if any step fails−119
;;; (some-> user−120
;;; (dict-ref _ name:)−121
;;; (string-split " " _)−122
;;; car)−123
;;;−124
;;; ;; Short-circuits on #f−125
;;; (some-> #f (+ 1 _)) ; => #f (doesn't call +)−126
;;;−127
;;; ;; Continues while truthy−128
;;; (some-> 5 (+ 1 _) (* 2 _)) ; => 12−129
;;; ```−130
(define-syntax some->−131
(syntax-rules ()−132
;; Base case: just the value−133
((some-> expr)−134
expr)−135
;; One or more steps: evaluate expr, check for #f, then continue−136
((some-> expr step rest ...)−137
(let ((%v expr))−138
(if %v−139
(some-> (-> %v step) rest ...)−140
#f)))))))+44
(import (sigil core))+45
(export chain -> some->))