; The problem that could be solved using metaprogramming
; techniques was discussed today on Newlisp forum. Programmer
; newdep proposed integration of unary predicates (the
; functions accepting only one argument and returning true or
; false) and "if" primitive. Instead of, for example, printing
; (if (integer? x) (print "integer!") (print "isn't integer"))
; newdep thought about following:
; (if-integer x (print "integer!) (print "isn't integer"))
; In further discussion it was noted that such macro would be
; smarter, but less general. Nevertheless, programmer cormullion
; suggested simple macro to accomplish that:
(define-macro (if-integer) (if (integer? (eval (args 0))) (eval (args 1)) (eval (args 2)))) (if-integer 34.5 (println "yes") (println "no")) ;--> "no"
; As this is routine operation, it can be used as good example
; of the techniqe that allows one to define lot of macros, related
; to all already defined predicates similar to if.
; It is already adressed in several posts, but this time, we
; have example of the code that could be processed easier
; in the form of a string, than in the form of s-expression.
; Usually, eval is better than eval-string, and McCarthy actually
; attributed relative success of Lisp to s-expressions, being simpler
; for metaprogramming, compared with normal strings as in POP
; for example.
; We'll first define helper function - almost the metapredicate:
; predicate predicate? Accepting symbol as argument, predicate?
; will check whether symbol ends with "?". Also, the predicate
; must be different than symbol '? itself which serves other
(define (predicate? i) (and (ends-with (string i) "?") (!= i '?)))
; Now we should loop through all predicates and do what cormullion
; done for integer. First, using strings and eval-string:
(dolist(i (symbols)) (when (predicate? i) (eval-string (replace "integer" (copy "(define-macro (if-integer) (if (integer? (eval (args 0))) (eval (args 1)) (eval (args 2))))") (append (chop (string i))))))) (if-zero 0 (println "yes") (println "no")) ;--> "yes"
; Then using s-expressions and eval
(dolist(i (symbols)) (when (predicate? i) ; for example, i=positive? (set (sym (append "if-" (chop (string i)))) ; positive?->if-positive (expand (lambda-macro() (if (i (eval (args 0))) (eval (args 1)) (eval (args 2)))) 'i)))) (if-zero 34 (println "yes") (println "no")) ;--> "no"