I am moving this blog to kazimirmajorinc.com.
In the meantime, some posts may be unavailable.

Where is Letex!

; It is easy to oversight letex as just another of less important
; relative of let. But letex is really different. It is perfect
; if we want to use macros as functions - the topic I discussed
; several times but not nearly exhausted. For example, "for" is
; the primitive that behaves as macro:

  (for (i 1 50) (print "*"))

  (println)

; (i 1 50) and (print i) are not evaluated before "for" is called.
; If they are, (i 1 50) would cause error. But, what if I want
; (for L (print i)) where L is random choice of three different
; lists, (i 1 10), (i 1 10 2), (i 10 1 -1)?
;
; The first guess,
;
; (set 'L (amb '(i 1 10) '(i 1 10 2) '(i 10 1 -1)))
; (for L (print i))
;
; results in ERR: list expected in function for : L.
;
; Standard way of doing that would be

  (set 'L (amb '(i 1 10) '(i 1 10 2) '(i 10 1 -1)))
  (eval (append '(for) (list L) '((print i))))

  (println)

; I constructed list (for (i 1 50) (print "*")) and evaluated it.
; Semantically, everything is OK, but syntactically, this expression
; is cumbersome. That's where letex come on stage:

  (letex ((L (amb '(i 1 10) '(i 1 10 2) '(i 10 1 -1))))
         (for L (print i)))

  (println)
  
; Much simpler. However, sometimes, I find that using letex is not
; that smooth and that I, more frequently than not, write my letex
; expressions starting from the back side, like I did in this example.

; Why? Because in mathematics, and ordinary language, word "where"
; is typically used for that task. And one writes the result first,
; with some variables with meaning he'll explain later.




; Really, even in formulation of this problem, I used that word:
; "where L is random choice." Because of that, I'll define macro
; "where." Actually, I'll define wherex and where, "for completeness",
; although I ; expect that I'll always need wherex. It is simple
; addition, but it can be useful.

(set 'where
   (lambda-macro()
      (eval (append '(let)
              (cons (last (args))
                (reverse (rest (reverse (args)))))))))

(set 'wherex
   (lambda-macro()
      (eval (append '(letex)
              (cons (last (args))
                (reverse (rest (reverse (args)))))))))


; Test:


(wherex (for condition body)
       ((condition (amb '(i 1 10) '(i 1 10 2) '(i 10 1 -1)))
        (body '(println i "-"))))
        
; It works.


(exit)


No comments:

Post a Comment