[HN Gopher] Functional Threading "Macros"
___________________________________________________________________
Functional Threading "Macros"
Author : GarethX
Score : 58 points
Date : 2025-10-06 10:46 UTC (1 days ago)
(HTM) web link (aartaka.me)
(TXT) w3m dump (aartaka.me)
| kazinator wrote:
| The main problem that threading macros solve is the lack of
| implicit partial application. If you farm that problem to
| partial-applicative combinators, you can do it:
| This is the TXR Lisp interactive listener of TXR 302. Quit
| with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet.
| 1> (defun bind1 (fn a1) (lambda (a2) [fn a1 a2])) bind1
| 2> (defun bind2 (fn a2) (lambda (a1) [fn a1 a2])) bind2
|
| We define bind1 and bind2 for binding the left or right argument
| of a binary function producing a unary function, then:
| 3> [chain [bind1 * 2] succ] #<intrinsic fun: 0 param +
| variadic> 4> [*3 10] 21
|
| The only wart is you have that explicit _bind1_.
|
| You can write functions that notice they have fewer arguments
| than ostensibly required and partially apply themselves.
| Obviously the standard * can't do that because it's usefully
| variadic already.
|
| Anyway, in the implementation of TXR, I've done this kind of
| thing in C, just with function calls: no macros. E.g. in eval.c,
| certain functions are prepared that the quasiquote expander uses:
|
| static val consp_f, second_f, list_form_p_f, quote_form_p_f;
| static val xform_listed_quote_f; static void
| qquote_init(void) { val eq_to_list_f =
| pa_12_1(eq_f, list_s); val eq_to_quote_f = pa_12_1(eq_f,
| quote_s); val cons_f = func_n2(cons);
| protect(&consp_f, &second_f, &list_form_p_f,
| "e_form_p_f, &xform_listed_quote_f, convert(val *, 0));
| eq_to_list_f = pa_12_1(eq_f, list_s); consp_f =
| func_n1(consp); second_f = func_n1(second);
| list_form_p_f = andf(consp_f,
| chain(car_f, eq_to_list_f, nao),
| nao); quote_form_p_f = andf(consp_f,
| chain(cdr_f, consp_f, nao),
| chain(cdr_f, cdr_f, null_f, nao),
| chain(car_f, eq_to_quote_f, nao),
| nao); xform_listed_quote_f = iffi(andf(consp_f,
| chain(car_f, eq_to_list_f, nao),
| chain(cdr_f, consp_f, nao),
| chain(cdr_f, cdr_f, null_f, nao),
| chain(cdr_f, car_f, consp_f, nao),
| chain(cdr_f, car_f, car_f, eq_to_quote_f, nao),
| nao), chain(cdr_f, car_f,
| cdr_f, pa_12_1(cons_f,
| nil), pa_12_2(cons_f,
| quote_s), nao),
| nil); }
|
| "nao" means "not an object": it's a sentinel value used
| internally in the runt-time for various purposes, the most common
| of them being the termination of variadic argument lists.
|
| andf is an and combinator: it returns a function which passes its
| argument(s) to each function in turn; if anything returns nil, it
| stops calling functions and returns nil. Otherwise it returns the
| value of the last function.
|
| The pa_this_that functions are partial applicator combinators,
| generalizations of bind1 and bind2. E.g. pa_12_1 means take a
| fucntion with arguments 1 2, returning a function which just
| takes 1 (so 2 is bound: this is like bind2). A bunch of these
| exist, and more coud be added if needed: pa_1234_1, pa_1234_34
| pa_123_1, pa_123_2, pa_123_3, pa_12_1 and pa_12_2.
| adityaathalye wrote:
| If the language allows passing lists of functions, then `comp`
| can be implemented by hand:
| https://clojuredocs.org/clojure.core/comp
|
| And re-implementing `comp` by hand can teach us more than we
| bargained for (all the way to compiler technology)... I blogged
| about it here: https://www.evalapply.org/posts/lessons-from-
| reimplementing-... ;; Clojure source code for
| `comp` (since Clojure v1.0) (defn comp "Takes a set
| of functions and returns a fn that is the composition of
| those fns. The returned fn takes a variable number of args,
| applies the rightmost of fns to the args, the next fn
| (right-to-left) to the result, etc." {:added "1.0"
| :static true} ([] identity) ([f] f) ([f
| g] (fn ([] (f (g))) ([x]
| (f (g x))) ([x y] (f (g x y))) ([x y z]
| (f (g x y z))) ([x y z & args] (f (apply g x y z
| args))))) ([f g & fs] (reduce1 comp (list* f g
| fs))))
| adityaathalye wrote:
| fogus has a couple of nice little posts on the threading macro
| itself...
|
| https://blog.fogus.me/2013/09/04/a-ha-ha-ha-aah.html
|
| https://blog.fogus.me/2009/09/04/understanding-the-clojure-m...
| adityaathalye wrote:
| Oh and, the arrow-kt library bolts this onto kotlin.
|
| Utilities for functions: https://arrow-kt.io/learn/collections-
| functions/utils/
___________________________________________________________________
(page generated 2025-10-07 23:01 UTC)