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