### Composition of Functions or Macros.

; The composition of the functions is one of the basic mathematical
; operations. In this post, I'll try to define composition of
; functions and macros (Newlisp macros=fexprs) in Newlisp.
;
; Such composition should satisfy the following:
;
;     ((composition 'f1 ... 'fn) _ _ _) = (f1 (f2 ... (fn _ _ _)))
;
; for all functions and macros.
;
; It wasn't that easy as I thought. First, I limited myself on the
; case of the composition of two functions. After some experimentation
; I came to that:

(set 'compose2 (lambda(f g)
(expand (lambda-macro()(letex((L (cons 'g (args))))(f L)))
'f 'g)))

; I tested it on simple example:

(println (compose2 'sin 'cos))

; (lambda-macro ()
;  (letex ((L (cons 'cos (args)))) (sin L)))

(println ((compose2 'sin 'cos) 3) (sin (cos 3))) ; OK, it works.

; Then I tested it on two special, well, entities, i.e. identity
; function and identity macro:

(set 'I (lambda(x)x))
(set 'IM (lambda-macro(x)x))

(println ((compose2 'I 'sin) 3)) ; 0.1411200081, as it should be, i.e. (I (sin 3))
(println ((compose2 'sin 'I) 3)) ; 0.1411200081, as it should be, i.e. (sin (I 3))
(println ((compose2 'IM 'sin) 3)) ; (sin 3), as it should be, i.e. (IM (sin 3))
(println ((compose2 'sin 'IM) 3)) ; 0.1411200081, as it should be (sin (IM 3))

; OK; it appears it worked. Now I'll have to solve multi-version,
; I.e. composition of many functions or macros

(set 'compose (lambda()
(case (length (args))
(0 I)               ; because (I (S x)) <=> (S x),
; no matter if S is function or macro
; so I can be always added from the left.
(1 (first (args)))
(2 (apply compose2 (args)))
(true (compose2 (first (args)) (apply compose (rest (args))))))))

(println ((compose sqrt) 65536)) ; 256
(println ((compose sqrt sqrt) 65536)) ; 16
(println ((compose sqrt sqrt sqrt) 65536)) ; 4

; OK, it works as well. However, result of the composing is
; rather complicated because of recursive definition

(println (compose 'f1 'f2 'f3 'f4))

; (lambda-macro ()
;   (letex ((L (cons '(lambda-macro ()(letex ((L (cons '(lambda-macro ()(letex ((L (cons 'f4 (args))))
;                                                                              (f3 L)))
;                                                      (args))))
;                                             (f2 L)))
;                    (args))))
;         (f1 L)))
;
;
; If iteration is used for definition of compose, then composition
; can be both shorter and faster - but not more elegant.

---