Reputation: 24545
The compose function applies last function first, i.e. it applies sent functions in reverse order. For example:
((compose sqrt add1) 8)
Above will add1 to 8 and then find sqrt of 9.
I want to create a mycompose function which applies first sent function first, and then second, third etc. Hence, in above example, sqrt needs to be applied first and then add1. I could manage following:
(define (mycompose L arg)
(let loop ((L L)
(res arg))
(cond
[(empty? L) res]
[else (loop (rest L) ((car L) res))])))
(mycompose (list sqrt add1) 8)
I am sure there is a better way. Especially, can above be achieved using macros and also permit multiple arguments to be sent to each function turn by turn?
Upvotes: 0
Views: 107
Reputation: 43852
This “reverse composition” that you describe is often called thrush, and the point-free package provides a thrush
function that does precisely what you want. However, let’s say you wanted to implement it yourself. Well, the easiest way would be to reuse the existing implementation of compose
, since thrush
is just compose
with the arguments reversed:
(define (thrush . fs)
(apply compose (reverse fs))
This is, in fact, how the point-free package implements thrush
. Still, this might be unsatisfying to you, since you don’t know how compose
is implemented. Well, fortunately, we can implement thrush
from scratch with a simple fold:
(define (thrush . fs)
(for/fold ([f values])
([g (in-list fs)])
(λ args (call-with-values (thunk (apply f args)) g))))
The real trick here is the use of call-with-values
, which properly handles functions that return multiple values. Just like Racket’s compose
, this will accept multiple values and pass them along to functions later in the pipeline as multiple arguments, creating a nice symmetry between function inputs and function outputs.
Upvotes: 4