I try to make my own (compose) function, but I can't get through it.
It needs to work as follow:
let's call that function "manual" - manual needs to take two arguments, and it has to compose them in a way that later we can call our manual like this: ((manual func1 func2) 1)
(so the output of the manual needs to be a procedure)
so if the func2 multiplies input by 2, and func1 raise it to the third power, then output of ((manual func1 func2) 1)
should be 8
(( 2*1)^3
)
I tried to write function like this:
(define (manual func1 func2)
(func1 (func2)) ; or f(g), or many other combinations of parenthesis
)
but unfortunately I couldn't came with idea of composing those two.
So I guess it needs to be a bit more abstract/complex than just some manipulation with parenthesis.
I want a function, manual
, that accepts two functions, f
and g
-
(define (manual f g)
...)
It should return a function, call it composition
-
(define (manual f g)
(define (composition ...)
...)
composition)
When composition
is applied to an argument, arg
, it should return a result of f
applied to arg
, where g
is applied to f
's result -
(define (manual f g)
(define (composition arg)
(g (f arg)))
composition)
Let's test it -
((manual
(lambda (x) (+ x 1))
(lambda (x) (* x 2)))
3)
8 ; (3 + 1) * 2
It would be nice if composition
didn't require a name. lambda
allows us to define a nameless, anonymous procedure -
(define (manual f g)
(lambda (arg)
(g (f arg))))
If I want to make the composition accept multiple arguments, I can use apply
to apply f
to all args
-
(define (manual f g)
(lambda args
(g (apply f args))))
((manual * add1) 10 20)
201 ; (10 * 20) + 1
If I want manual
to accept any number of functions, I can rewrite the composition to apply all of them in sequence using a left fold -
(define (manual f . more)
(lambda args
(foldl (lambda (f x) (f x))
(apply f args)
more)))
((manual * add1 add1 add1 add1 add1) 10 20)
205 ; (((((10 * 20) + 1) + 1) + 1) + 1) + 1
Above special behaviour is given to the first function in the sequence. If I want to make manual
generic, I can ask the caller to handle the specialized behaviour -
(define (manual . funcs)
(lambda (init)
(foldl (lambda (f x) (f x))
init
funcs)))
((manual
(curry apply *) ; specific behaviour
add1
add1
add1
add1
add1)
(list 10 20)) ; multiple arguments collected in a list
205 ; (((((10 * 20) + 1) + 1) + 1) + 1) + 1
@PeterWinton points out that a typical compose function will apply the functions in right-to-left order. The manual
procedure we wrote above applies them left-to-right. It's worth knowing the difference and what's considered common in practice. Writing manual
to reflect this behaviour remains an exercise for the reader.