Last active
May 30, 2020 04:27
-
-
Save vseloved/4432594 to your computer and use it in GitHub Desktop.
List comprehensions with a syntax very close to set-theoretic notation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defun read-listcomp (stream char) | |
(declare (ignore char)) | |
(let (rezs srcs conds state) | |
(dolist (item (read-delimited-list #\} stream)) | |
(if (eql '|| item) | |
(setf state (if state :cond :src)) | |
(case state | |
(:src (push item srcs)) | |
(:cond (push item conds)) | |
(otherwise (push item rezs))))) | |
(setf rezs (reverse rezs) | |
srcs (reverse srcs) | |
conds (reverse conds)) | |
(let ((binds (mapcar (lambda (group) (cons (first group) (third group))) | |
(group 3 srcs)))) | |
`(mapcan (lambda ,(mapcar #'car binds) | |
(when (and ,@conds) | |
(list ,(if (rest rezs) | |
(cons 'list rezs) | |
(first rezs))))) | |
,@(mapcar #'cdr binds))))) | |
(set-macro-character #\{ #'read-listcomp) | |
(set-macro-character #\} (get-macro-character #\))) | |
;; Exmaples: | |
;; CL-USER> { x || x <- (loop :for i :upto 10 :collect i) } | |
;; (0 1 2 3 4 5 6 7 8 9 10) | |
;; CL-USER> {x || x <- '(1 nil 2) || x} | |
;; (1 2) | |
;; CL-USER> {x y || x <- '(1 2 3) y <- '(5 6 7) || (oddp x) (> y 5)} | |
;; ((3 7)) | |
;; CL-USER> { (+ x y) || x <- '(1 2 3) y <- '(5 6 7) || (oddp x) (> y 5) } | |
;; (10) | |
;; GROUP is borrowed from Paul Graham's On Lisp | |
(defun group (n list) | |
"Split LIST into a list of lists of length N." | |
(declare (integer n)) | |
(when (zerop n) | |
(error "Group length N shouldn't be zero.")) | |
(labels ((rec (src acc) | |
(let ((rest (nthcdr n src))) | |
(if (consp rest) | |
(rec rest (cons (subseq src 0 n) acc)) | |
(nreverse (cons src acc)))))) | |
(when list | |
(rec list nil)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment