;; Clojure's when-let using Lisp-style macros.
(use-modules (language tree-il))
(define (display-macroexpand expr)
(display (tree-il->scheme (macroexpand expr)))
(newline))
;; when-let.
(define-macro (when-let bindings . body)
(unless (= (length bindings) 1)
(error "call to when-let did not conform to spec"))
`(let (,@bindings)
(when ,(caar bindings)
,@body)))
(display-macroexpand '(when-let ((x (= 1 1))) x))
(display-macroexpand '(when-let ((x (= 1 1))) x x))
(display-macroexpand '(when-let ((x (= 1 1))) x (x (x))))
(when-let ((x #f))
(format #t "!:<~S>~%" x))
(when-let ((x #t))
(format #t "t:<~S>~%" x))
(when-let ((x (= 1 2)))
(format #t "!:<~S>~%" x))
(when-let ((x (= 1 1)))
(format #t "t:<~S>~%" x))
(when-let ((x (+ 1 1)))
(format #t "2:<~S>~%" x))
;; when-let using gensym (unnecessary).
;; @note The body needs access to the generated symbols.
(define (subst new old tree equal)
(let loop ((tree tree))
(cond
((equal tree old) new)
((pair? tree)
(cons (loop (car tree))
(loop (cdr tree))))
(else tree))))
(define-macro (when-let bindings . body)
(unless (= (length bindings) 1)
(error "call to when-let did not conform to spec"))
(let ((g (gensym)))
`(let (,@(subst g (caar bindings) bindings eq?))
(when ,g
,@(subst g (caar bindings) body eq?)))))
(display-macroexpand '(when-let ((x (= 1 1))) x))
(display-macroexpand '(when-let ((x (= 1 1))) x x))
(display-macroexpand '(when-let ((x (= 1 1))) x (x (x))))
(when-let ((x #f))
(format #t "!:<~S>~%" x))
(when-let ((x #t))
(format #t "t:<~S>~%" x))
(when-let ((x (= 1 2)))
(format #t "!:<~S>~%" x))
(when-let ((x (= 1 1)))
(format #t "t:<~S>~%" x))
(when-let ((x (+ 1 1)))
(format #t "2:<~S>~%" x))