Skip to content

Instantly share code, notes, and snippets.

@ehaliewicz
Last active October 14, 2015 00:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ehaliewicz/4283542 to your computer and use it in GitHub Desktop.
Save ehaliewicz/4283542 to your computer and use it in GitHub Desktop.
a simple function threading macro
(defmacro -> (init &rest funcs)
(cond
((null funcs) `,init)
((eql 'if (car funcs))
(let* ((gensym (gensym)))
`(-> (let ((,gensym ,init))
(if ,gensym (-> ,gensym ,(cadr funcs))
(-> ,gensym ,(caddr funcs)))
,@(cdddr funcs)))))
((and (consp (car funcs)) (not (eql 'lambda (caar funcs))))
(let* ((gensym (gensym))
(func (recursive-replace '_ `,gensym (car funcs))))
`(let ((,gensym ,init)) (-> ,func ,@(cdr funcs)))))
(t `(-> (,(car funcs) ,init) ,@(cdr funcs)))))
(defun recursive-replace (item replace form)
(loop for form in form collect
(if (consp form)
(recursive-replace item replace form)
(if (eql form item)
replace
form))))
(-> 3 square sqrt)
;; macroexpands to
(sqrt (square 3))
;; it also supports (simple) pattern matching
;; any _ in a expression are replaced by the value of the previous expression
(-> 2 + / (lambda (x) (* x _)))
;; macroexpands to
(LET ((#:G1018 (/ (+ 2))))
(LAMBDA (#:G1018) (* X X)))
;; which is essentially
((lambda (x) (* x x)) (/ (+ 2)))
(-> 2 (- 2) (+ _ 4) (/ _ 2))
;; macroexpands to
(let ((#:G1023 2))
(let ((#:G1025 (+ #:G1023 4)))
(/ #:G1025 2)))
;; which is esentially
(/ (+ (- 2 2) 4) 2)
(-> 3 signum plusp if print (print "false"))
-> t
(-> -3 signum plusp if print (print "false"))
-> "false"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment