;===============================================================
; CONVERSION OF FUNCTIONS TO MACROS AND VICE VERSA
;
;
; If you think on the way I do, then you sometimes have the function,
; and you want macro - to avoid using of one extra quote in the
; function call. Or, you have a macro, and you want function to pass
; it value stored in some variable.
; In this post, I'll define two cute functions for exactly that purpose;
;
; macro-from-function
; function-from-macro
; Lets start with one meaningless function and macro for illustration
; of the idea.
(set 'set-first-to-0-function
(lambda()
(set-nth ((first (args)) 0) 0)))
(set 'set-last-to-0-macro
(lambda-macro()
(set-nth ((first (args)) -1) 0)))
; The definitions are nearly equal, the difference is
; in the way we call these two:
(println (set-first-to-0-function '(1 2 3 4 5))) ; (0 2 3 4 5)
(println (set-last-to-0-macro (1 2 3 4 5))) ; (1 2 3 4 0)
;---------------------------------------------------------------
; The similarity of these two definitions is striking, but it
; is not completely trivial to convert one to another - because
; lambda and lambda-macro definitions are not simply lists with
; the first elements lambda or lambda-macro. They are more something
; like special kinds of lists, as it can be seen from following
; expressions:
(println (first (lambda(x)(print x)))) ;(x)
(println (rest (lambda(x)(print x)))) ;((print x))
; Cons can surprise you:
(println (cons (lambda-macro) (lambda()(print))))
(lambda (lambda-macro ) () (print))
; But append behaves nice, so, it is maybe the most natural
; way to exchange lambda and lambda-macro:
(println (append (lambda-macro) (lambda(x)(print x))))
; result: (lambda-macro(x)(print x))
(set 'function-from-macro (lambda()
(append '(lambda) ; quote can be omitted
(first (args)))))
(set 'macro-from-function (lambda()
(append '(lambda-macro)
(first (args)))))
;---------------------------------------------------------------
; Does it work?
(set 'set-first-to-0-macro
(macro-from-function set-first-to-0-function))
(set 'set-last-to-0-function
(function-from-macro set-last-to-0-macro))
(println (set-first-to-0-macro (1 2 3 4 5))) ; (0 2 3 4 5)
(println (set-last-to-0-function '(1 2 3 4 5))) ; (1 2 3 4 0)
;===============================================================
; CONVERSION OF BUILT-INS to LAMBDA AND LAMBDA-MACRO EXPRESSIONS.
; In Newlisp, there is no clear distinction between built in
; functions and built in macros. The program cannot test whether
; built in is function or macro, and in the reference manual,
; all of them are called functions. But some of the built ins
; really behave as functions, while some behave more like
; macros. For example, "reverse" is function. You have to call it
; with argument that evaluate to list, not list itself.
(println (reverse '(1 2 3)))
; Unlike "reverse", "for" behaves like macro:
(for (i 7 9) (println i))
; obviously, the expressions (i 7 9) and (println i) are not evaluated
; prior to the call of the "for."
;
; So, one might want to use macro version of reverse, something like
;
; (reverse-macro (1 2 3))
;
; or functional version of for:
;
; (for-function '(i 7 9) '(println i))
;
; Unfortunately, our function-from-macro and macro-from-function
; do not work for "reverse" and "for." They need lambda and
; lambda-macro expressions.
; We'll solve this problem by writing two functions that transform
; built in functions in lambda expressions, and built in macros in
; lambda-macro expressions. After that, function-from-macro and
; macro-from-function can be applied.
; How can we define the lambda and lambda-macro expressions
; doing exactly the same thing as reverse and for?
; These are some possibilities:
(lambda()
(apply 'reverse $args))
(lambda-macro()
(eval (cons 'for $args)))
; Let's test it:
(println "======================================================")
(println ((lambda()
(apply 'reverse $args))
'(1 2 3)))
; and
((lambda-macro()
(eval (cons 'for $args)))
(i 7 9)
(println i))
; RESULT:
; (3 2 1)
; 7
; 8
; 9
; It works.
; It is obviously the trick; but it serves its purpose.
; Now, we can automatize such transformation of built-ins into
; equivalent lambda and lambda-macro expressions:
(println "======================================================")
(set 'lambda-form
(lambda(built-in-name)
(expand '(lambda()(apply 'built-in-name $args))
'built-in-name)))
(set 'lambda-macro-form
(lambda(built-in-name)
(expand '(lambda-macro()(eval (cons 'built-in-name $args)))
'built-in-name)))
; Does it work?
(set 'reverse-macro (macro-from-function (lambda-form 'reverse)))
(set 'for-function (function-from-macro (lambda-macro-form 'for)))
(println (reverse-macro (1 2 3)))
(for-function '(i 1 100) '(print i))
; It does.
(exit)
Conversions to Functions and Macros.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment