iterate(iter)を使ってみる
loopの強力版といったところ。
loopとの比較
iterにuptoがないのはびっくりしたがほかはほとんど自然に翻訳できる。
loopのif/when/unlessはanaphoricになっているが、iterは自分でbindしないといけない。
hashの巡回が自然なのがいい。loop版はダサすぎる。
(require 'iterate) (in-package :iter) ;;;; loop vs iter ;; for = as (defun at-most-3times (list) (loop for item in list for i from 1 to 3 collect (format nil "<~a>" item))) (defun at-most-3times (list) (iter (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) (iter (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) (iter (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) (iter (for i upto 10) (collect i)) ; Unknown keyword UPTO (loop for i to 10 collect i) ; => (0 1 2 3 4 5 6 7 8 9 10) (iter (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) (iter (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) (iter (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) (iter (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) (iter (repeat 3) (collect 1)) ; => (1 1 1) (loop for i in '(10 20) collect (* i 9)) ; => (90 180) (iter (for i in '(10 20)) (collect (* i 9))) ; => (90 180) (loop for i in '(10 20 30 40) collect i) ; => (10 20 30 40) (iter (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) (iter (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) (iter (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)) (iter (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)) (iter (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)) (iter (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) (iter (for x across "abcd") (collect x)) ; Unknown keyword ACROSS (iter (for x in-vector "abcd") (collect x)) ; => (#\a #\b #\c #\d) (iter (for x in-string "abcd") (collect x)) ; => (#\a #\b #\c #\d) (iter (for x in-sequence "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 ;; 長っ!! (setq hash (let ((h (make-hash-table))) (setf (gethash 1 h) 'one) (setf (gethash 2 h) 'two) h)) ; {1:one, 2:two} (loop for k being the hash-keys in hash using (hash-value v) collect (cons k v)) ; => ((1 . ONE) (2 . TWO)) (loop for v being the hash-values in hash using (hash-key k) collect (cons k v)) ; => ((1 . ONE) (2 . TWO)) ;; iterのほうが自然。loopのはかっこわるい。 (iter (for (k v) in-hashtable hash) (collect (cons k v))) ; => ((1 . ONE) (2 . TWO)) ;; it (loop for key in '(1 3 2 5) when (gethash key hash) collect it) ; => (ONE TWO) (iter (for key in '(1 3 2 5)) (with it) (when (setf it (gethash key hash)) (collect it))) ; => (ONE TWO) (iter (for key in '(1 3 2 5)) (for it = (gethash key hash)) (when it (collect it))) ; => (ONE TWO) ;; use anaphoric macro (defmacro aif (test-form then-form &optional else-form) `(let ((it ,test-form)) (if it ,then-form ,else-form))) (defmacro awhen (test-form &body body) `(aif ,test-form (progn ,@body))) (iter (for key in '(1 3 2 5)) (awhen (gethash key hash) (collect it))) ; => (ONE TWO) ;; for - initially / for - first (let ((list '(9 8)) (num 9999)) (iter (for num in list) (for i first num then (1+ i)) ; 前節に依存するので num == 9 (collect (cons i num)))) ; => ((9 . 9) (10 . 8)) (let ((list '(9 8)) (num 9999)) (iter (for num in list) (for i initially num then (1+ i)) ; iterの外側で評価されるので num == 9999のはずなのに (collect (cons i num)))) ; なぜかエラー。 ;; 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)) (iter (repeat 5) (for x initially 0 then y) ; first でもよい (for y initially 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)) (iter (repeat 5) (for y initially 1 then (+ x y)) (for x initially 0 then y) (collect (cons x y))) ; => ((0 . 1) (1 . 1) (2 . 2) (4 . 4) (8 . 8)) (iter (repeat 5) (for y first 1 then (+ x y)) (for x first 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) (iter (repeat 5) (for x first 0 then y) (for px previous x) ;前のx (for y first 1 then (+ px 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") (iter (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 (iter (for x from 1 to 4) (when (evenp x) (sum x))) ; => 6 (loop for x from 1 to 4 unless (evenp x) sum x) ; => 4 (iter (for x from 1 to 4) (unless (evenp x) (sum x))) ; => 4 ;; named (setq lists '((20 12) (6 7 120))) (loop named outer for list in lists do (loop for item in list do (if (oddp item) (return-from outer item)))) ; => 7 (iter outer (for list in lists) (iter (for item in list) (if (oddp item) (return-from outer item)))) ; => 7 ;; initially, finally ;; while, until, always, never, thereis (loop for n in '(2 4 6) always (evenp n)) ; => T (iter (for n in '(2 4 6)) (always (evenp n))) ; => T (loop for n in '(2 4 6) never (oddp n)) ; => T (iter (for n in '(2 4 6)) (never (oddp n))) ; => T (loop for char across "abc123" thereis (digit-char-p char)) ; => 1 (iter (for char in-string "abc123") (thereis (digit-char-p char))) ; => 1 (loop for char across "abcdef" thereis (digit-char-p char)) ; => NIL (iter (for char in-string "abcdef") (thereis (digit-char-p char))) ; => NIL
高度な機能
以前、loopで足して最大になる数字の組を求めようとしたが、無理っぽかった。
iterだとそれが可能になる。
iterに出会う前までloopに萌えていたが、乗り換えることにした。
Rolling Your Own - The Iterate Manualによると新しくclauseを作ることができる。
難しいので今はパス。
以下の紹介ではloopにはないであろう機能も含まれている。
;; sum / declare (iter (for i from 1 to 10) (sum i)) ; => 55 (iter (for i from 1 to 10) (sum i into x) (declare (x fixnum)) (finally (return x))) ; => 55 ;; factorial 6! / reducing (iter (for i from 1 to 4) (multiply i)) ; => 24 (iter (for i from 1 to 4) (reducing i by #'*)) ; => 24 (iter (for i from 1 to 4) (reducing i by #'* initial-value 1)) ; => 24 ;; collect (iter (for i from 1 to 5) (collect i)) ; => (1 2 3 4 5) (iter (for i from 1 to 5) (collect i at end)) ; => (1 2 3 4 5) (iter (for i from 1 to 5) (collect i at beginning)) ; => (5 4 3 2 1) (iter (for i from 1 to 5) (collect i result-type vector)) ; => #(1 2 3 4 5) ;; adjoining (iter (for x in '(1 1 2 2 3)) (adjoining x)) ; => (1 2 3) (iter (for x in '(1 1 2 2 3)) (adjoining x test #'= at end result-type vector)) ; => #(1 2 3) ;; appending/nconcing/unioning/nunioning (iter (for l in '((1 1 2)(2 3 3))) (appending l)) ; => (1 1 2 2 3 3) (iter (for l in '((1 1 2)(2 3 3))) (nconcing l)) ; => (1 1 2 2 3 3) (iter (for l in '((1 1 2)(2 3 3))) (unioning l)) ; => (1 1 2 3 3) (iter (for l in '((1 1 2)(2 3 3))) (nunioning l)) ; => (1 1 2 3 3) (union '(1 1 2) '(2 3 3)) ; => (1 1 2 3 3) (iter (for i from 1 to 4) (accumulating i by #'* initial-value 1)) ; => 24 ;; finding such-that (iter (for i from 1 to 4) (finding i such-that #'evenp)) ; => 2 (iter (for i from 1 to 4) (if (evenp i) (collecting i))) ; => (2 4) ;; finding (min|max)imizing (min|max)imizeではダメ! (iter (for pair in '((1 . 10)(2 . 3)(4 . 6))) (for (a . b) = pair) (finding pair maximizing (+ a b))) ; => (1 . 10) (iter (for pair in '((1 . 10)(2 . 3)(4 . 6))) (for (a . b) = pair) (for sum = (+ a b)) (finding (list sum pair) maximizing sum)) ; => (11 (1 . 10)) (iter (for i in '(7 -4 2 -3)) (if (plusp i) (finding i such-that (evenp i)) (finding (- i) such-that (oddp i)))) ; => 2 ;; if-first-time (iter (for i in '(1 2 3)) (if-first-time (collect i into 1st) (collect i into last)) (finally (return (list 1st last)))) ; => ((1) (2 3)) ;; initially, after-each, else, finally, finally-protected (iter (with sum) (with i) (initially (setf sum 0 i 1)) (while (<= i 10)) (incf sum i) (after-each (incf i)) (finally (return sum))) ; => 55 (iter (with loop-is-executed = nil) (until t) (setf loop-is-executed t) (else (setf loop-is-executed 'not-executed) (return loop-is-executed)) (finally (return 'executed))) ; => NOT-EXECUTED (iter (with loop-is-executed = nil) (for i from 1 to 2) (setf loop-is-executed t) (else (setf loop-is-executed 'not-executed) (return loop-is-executed)) (finally (return 'executed))) ; => EXECUTED ;; finally-protectedはよくわからん。returnできない… ;; next-iteration, finish (iter (for c in-string "ab123!24") (unless (digit-char-p c) (next-iteration)) (collect c)) ; => (#\1 #\2 #\3 #\2 #\4) (iter (for c in-string "ab123!24") (if (char= c #\!) (finish)) (unless (digit-char-p c) (next-iteration)) (collect c)) ; => (#\1 #\2 #\3) ;; leave (iter (for i from 1 to 10) (leave i)) ; => 1 ;; multiple accumulattion (iter (for i from 1 to 3) (collect i into nums) (collect (sqrt i) into nums) (finally (return nums))) ; => (1 1.0 2 1.4142135 3 1.7320508) (iter (for i from 1 to 3) (collect i) (collect (sqrt i))) ; => (1 1.0 2 1.4142135 3 1.7320508) ;; in (nested iter) (iter (for i from 1 to 2) (iter (for j from 1 to 3) (collect (cons i j)))) ; => NIL (wrong version) (iter outer (for i from 1 to 2) (iter (for j from 1 to 3) (in outer (collect (cons i j))))) ; => ((1 . 1) (1 . 2) (1 . 3) (2 . 1) (2 . 2) (2 . 3))