; 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
; purposes.

(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)

        (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))))

(if-zero 34 (println "yes") (println "no")) ;--> "no"


No comments:

Post a Comment