loopの奥深さを知る

loopマクロってほんとにすごい。究極の言語内DSL。ここまでくるともう芸術品としか言えない。
loopをキモいと言うLisperは多そうだけど、それが設計できるのがLispなんだろう。
いろいろな例をREPLで実行中。結果は後でさっと見られるようにusage-memoに書いておく。

;; for = as
(defun at-most-3times (list)
  (loop for item in list
        for i from 1 to 3
     collect (format nil "<~a>" item)))
(at-most-3times '(1 2 3 4))             ; ("<1>" "<2>" "<3>")
(at-most-3times '(1 2))                 ; ("<1>" "<2>")

;; from downfrom upfrom 
;; to upto below downto above
;; by

(loop for i from 1 to 3 collecting i)      ; (1 2 3)
(loop for i from 1 to 5 by 2 collect i)    ; (1 3 5)
;; 0-origin
(loop for i upto 10 collect i)          ; (0 1 2 3 4 5 6 7 8 9 10)
(loop for i to 10 collect i)            ; (0 1 2 3 4 5 6 7 8 9 10)
(loop for i from 0 downto -10 collect i) ; (0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10)
(loop for i below 10 collect i)          ; (0 1 2 3 4 5 6 7 8 9)
(loop for i from 0 above -10 collect i) ; (0 -1 -2 -3 -4 -5 -6 -7 -8 -9)

(loop repeat 3 collect 1)               ; (1 1 1)

(loop for i in '(10 20) collect (* i 9)) ; (90 180)
(loop for i in '(10 20 30 40) collect i) ; (10 20 30 40)
(loop for i in '(10 20 30 40) by #'cdr collect i)  ; (10 20 30 40)
(loop for i in '(10 20 30 40) by #'cddr collect i) ; (10 30)
(loop for i on '(10 20 30 40) collect i) ; ((10 20 30 40) (20 30 40) (30 40) (40))
(loop for i on '(10 20 30 40) by #'cdr collect i)  ; ((10 20 30 40) (20 30 40) (30 40) (40))
(loop for i on '(10 20 30 40) by #'cddr collect i) ; ((10 20 30 40) (30 40))

(loop for x across "abcd" collect x)    ; (#\a #\b #\c #\d)

;; the = each / of = in / singular
;; for var being the hash-keys in hash
;; for var being the hash-values in hash
;; for var being the symbols in package
;; for var being the present-symbols in package
;; for var being the external-symbols in package
;; 長っ!!
(loop for k being the hash-keys in hash using (hash-values v) ...)
(loop for v being the hash-values in hash using (hash-key k) ...)

;; do* みたいなの
;; x: 0 1 2 4 8
;; y: 1 2 4 8 16
(loop repeat 5
   for x = 0 then y
   for y = 1 then (+ x y)
   collect (cons x y))                  ; ((0 . 1) (1 . 2) (2 . 4) (4 . 8) (8 . 16))
;; y: 1 1 2 4 8
;; x: 0 1 2 4 8
(loop repeat 5
   for y = 1 then (+ x y)
   for x = 0 then y
   collect (cons x y))                  ; ((0 . 1) (1 . 1) (2 . 2) (4 . 4) (8 . 8))
;; do みたいなの fibonacci
;; x: 0 1 1 2 3
;; y: 1 1 2 3 5
(loop repeat 5
   for x = 0 then y
   and y = 1 then (+ x y)
   collect y)                           ; (1 1 2 3 5)

;; with var = expr

;; destructing
(loop for (a b) in '((1 2)(3 4)(5 6)) collect
     (format nil "a:~a, b:~a" a b))     ; ("a:1, b:2" "a:3, b:4" "a:5, b:6")

;; collect, append, nconc, count, sum, maximize, minimize

;; return
;; finally

;; when, if, unless
(loop for x from 1 to 4 when (evenp x) sum x) ; 6
(loop for x from 1 to 4 if (evenp x) sum x) ; 6
(loop for x from 1 to 4 unless (evenp x) sum x) ; 4
;; it
(loop for key in some-list
     when (gethash key some-hash)
     collect it)
;; named
(loop named outer for list in lists do
     (loop for item in list do
          (if (what-i-am-looking-for-p item)
              (return-from outer item))))
;; initially, finally
;; while, until, always, never, thereis
(loop for n in '(2 4 6) always (evenp n)) ; T
(loop for n in '(2 4 6) never (oddp n)) ; T
(loop for char across "abc123" thereis (digit-char-p char)) ; 1
(loop for char across "abcdef" thereis (digit-char-p char)) ; NIL