;; 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))))
>The language I’m using in this post is Lamber, my Lambda Calculus compiling language. It features a minimalist syntax with only functions, values, if-s, and operators like Wisp’s colon nesting operator and terminating period (similar to Lua’s end.)
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:
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;
"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.
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-...
Oh and, the arrow-kt library bolts this onto kotlin.
Utilities for functions: https://arrow-kt.io/learn/collections-functions/utils/
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...
Starts with saying they like Common Lisp but use Clojure daily, then proceeds with some language called "lamber". What?
From the post:
>The language I’m using in this post is Lamber, my Lambda Calculus compiling language. It features a minimalist syntax with only functions, values, if-s, and operators like Wisp’s colon nesting operator and terminating period (similar to Lua’s end.)
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:
We define bind1 and bind2 for binding the left or right argument of a binary function producing a unary function, then: 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;
"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.