4 ms·
Or with more Python-esque syntax: (let ((files (coerce "ABCDEFGH" 'list)) (ranks (loop for r from 1 to 9 collect r))) [(format nil "~a~a" f
by Jach 5mo ago
Or with more Python-esque syntax:
(let ((files (coerce "ABCDEFGH" 'list))
(ranks (loop for r from 1 to 9 collect r)))
[(format nil "~a~a" file rank) (file <- files) (rank <- ranks)])
Based on the list comprehension macro from 1991 in https://3e8.org/pub/scheme/doc/lisp-pointers/v4i2/p16-lapalme.pdf https://3e8.org/pub/scheme/doc/lisp-pointers/v4i2/p16-lapalm... that still works.
(defmacro comp ((e &rest qs) l2)
(if (null qs) `(cons ,e ,l2) ; rule A
(let ((q1 (car qs))
(q (cdr qs)))
(if (not (eq (cadr q1) '<-)) ; a generator?
`(if ,q1 (comp (,e ,@q) ,l2) ,l2) ; rule B
(let ((v (car q1)) ; rule C
(l1 (third q1))
(h (gentemp "H-"))
(us (gentemp "US-"))
(us1 (gentemp "US1-")))
`(labels ((,h (,us) ; corresponds to a letrec
(if (null ,us) ,l2
(let ((,v (car ,us))
(,us1 (cdr ,us)))
(comp (,e ,@q) (,h ,us1))))))
(,h ,l1)))))))
(defun open-bracket (stream ch)
(do ((l nil)
(c (read stream t nil t)(read stream t nil t)))
((eq c '|]|) `(comp ,(reverse l) ()))
(push c l)))
(defun closing-bracket (stream ch) '|]|)
(set-macro-character #\[ #'open-bracket)
(set-macro-character #\] #'closing-bracket)
Supports filtering too, e.g.
(let ((xs '(1 2 3 4))
(ys '(1 2 3 4)))
[(+ x y) (x <- xs) (y <- ys) (evenp x) (oddp y)])
; -> (3 5 5 7)
- aidenn0 5mo agoI didn't try macroexpanding it yet, but when I make the 9 a runtime-parameter, I eventually get a stack-overflow with SBCL not TCO-ing the "H" binding in labels. The comments make me think this is ported from scheme, which has precise TCO rules. [edit] macroexpanded: (LABELS ((H-37 (US-38) (IF (NULL US-38) NIL (LET ((FILE (CAR US-38)) (US1-39 (CDR US-38))) (LABELS ((H-43 (US-44) (IF (NULL US-44) (H-37 US1-39) (LET ((RANK (CAR US-44)) (US1-45 (CDR US-44))) (CONS (FORMAT NIL "~a~a" FILE RANK) (H-43 US1-45)))))) (H-43 RANKS)))))) (H-37 FILES))