; One of the well known advantages of special operators over
; functions is that special operators apply "short-cuirciting".
; For example, operator "and" that evaluates
; (and (= 1 1) (= 2 2) (= 3 4) (= 5 (slow-function 6)))
; will never evaluate clause (= 5 (slow-function 6)). Instead,
; after (= 3 4) is recognized to be false, there is no theoretical
; possibility that whole expression evaluates to true, and
; nil is returned without evaluating other clauses.
; This is significant difference between operators and functions.
; If "and" was defined as function, all clauses would be evaluated
; first, and then passed to the operator "and."
; Only today I came to idea to test whether operator compose I
; defined few days ago, which can be applied on fexprs as well as
; on functions, preserves short-circuiting.
; I'll test it by defining two well known logical operators,
; nor and nand.
(set 'nor (compose not or))
(set 'nand (compose not and))
; Let us test whether 'nor' and 'nand' preserve short-circuit
(nand (println "this should be done ")
(println "and this should be done")
(println (setf j nil))
(println "but this shouldn't be done"))
; this should be done
; and this should be done
(nor (println (= 1 2))
(println (= 1 3))
(println "and something different")
(println "this shouldn't be done"))
; and something different
; Everything works. Beautiful, isn't it?
Bad weather in Croatia.
; 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)))
; 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)))
; (f2 L)))
; (f1 L)))
; If iteration is used for definition of compose, then composition
; can be both shorter and faster - but not more elegant.
Alan Kay on Lisp and Fexprs
|Alan Kay is designer of Smalltalk. This citation is known, but not as well as it should be, and I think it deserves attention separately of many posts I wrote on fexprs.|
|If you liked this article, you might be interested in On Pitman's 'Special forms in Lisp'.|