Skip to content

Instantly share code, notes, and snippets.

@cqfd
Last active December 10, 2015 04:28
Show Gist options
  • Save cqfd/4380866 to your computer and use it in GitHub Desktop.
Save cqfd/4380866 to your computer and use it in GitHub Desktop.
List comprehensions, @darius style.
;; An Emacs Lisp port of Darius Bacon's list comprehension macro.
(setq lexical-binding t)
(defmacro for (bindings body)
(declare (indent defun))
(expand-for bindings body '(lambda () ())))
(defun expand-for (bindings body rest-var)
(if (null bindings)
`(cons ,body (funcall ,rest-var))
(case (car bindings)
(:while
`(if ,(cadr bindings)
,(expand-for (cddr bindings) body rest-var)
'()))
(:when
`(if ,(cadr bindings)
,(expand-for (cddr bindings) body rest-var)
(funcall ,rest-var)))
(:let
`(let (,(cadr bindings))
,(expand-for (cddr bindings) body rest-var)))
(otherwise
(let ((sub-var (gensym)))
`(foldr-lazy (lambda (,(car bindings) ,sub-var)
,(expand-for (cddr bindings) body sub-var))
,rest-var
,(cadr bindings)))))))
(defun foldr-lazy (f z-thunk xs)
(if (null xs)
(funcall z-thunk)
(funcall f (car xs) (lambda ()
(foldr-lazy f z-thunk (cdr xs))))))
;; Examples
(for (x '(1 2 3))
x)
;; => (1 2 3)
(for (x '(1 2 3) :while (< x 2))
x)
;; => (1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment