common-lisp
LOOP, 반복을위한 Common Lisp 매크로
수색…
바운드 루프
우리는 사용하여 작업을 여러 번 어떤 수를 반복 할 수 있습니다 repeat
.
CL-USER> (loop repeat 10 do (format t "Hello!~%")) Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! Hello! NIL CL-USER> (loop repeat 10 collect (random 50)) (28 46 44 31 5 33 43 35 37 4)
순차 반복
(loop for i in '(one two three four five six)
do (print i))
(loop for i in '(one two three four five six) by #'cddr
do (print i)) ;prints ONE THREE FIVE
(loop for i on '(a b c d e f g)
do (print (length i))) ;prints 7 6 5 4 3 2 1
(loop for i on '(a b c d e f g) by #'cddr
do (print (length i))) ;prints 7 5 3 1
(loop for i on '(a b c)
do (print i)) ;prints (a b c) (b c) (c)
(loop for i across #(1 2 3 4 5 6)
do (print i)) ; prints 1 2 3 4 5 6
(loop for i across "foo"
do (print i)) ; prints #\f #\o #\o
(loop for element across "foo"
for i from 0
do (format t "~a ~a~%" i element)) ; prints 0 f\n1 o\n1 o
다음은 키워드 요약입니다.
예어 | 시퀀스 유형 | 변수 유형 |
---|---|---|
...에서 | 명부 | 목록의 요소 |
...에 | 명부 | 목록의 일부 cdr |
건너서 | 벡터 | 벡터의 요소 |
해시 테이블에 대한 루핑
(defvar *ht* (make-hash-table))
(loop for (sym num) on
'(one 1 two 2 three 3 four 4 five 5 six 6 seven 7 eight 8 nine 9 ten 10)
by #'cddr
do (setf (gethash sym *ht*) num))
(loop for k being each hash-key of *ht*
do (print k)) ; iterate over the keys
(loop for k being the hash-keys in *ht* using (hash-value v)
do (format t "~a=>~a~%" k v))
(loop for v being the hash-value in *ht*
do (print v))
(loop for v being each hash-values of *ht* using (hash-key k)
do (format t "~a=>~a~%" k v))
단순 루프 폼
특별한 키워드가없는 간단한 루프 형태 :
(loop forms...)
루프를 빠져 나가려면 (return <return value>)
사용할 수 있습니다.
몇 가지 예 :
(loop (format t "Hello~%")) ; prints "Hello" forever
(loop (print (eval (read)))) ; your very own REPL
(loop (let ((r (read)))
(typecase r
(number (return (print (* r r))))
(otherwise (format t "Not a number!~%")))))
패키지 루핑
(loop for s being the symbols in 'cl
do (print s))
(loop for s being the present-symbols in :cl
do (print s))
(loop for s being the external-symbols in (find-package "COMMON LISP")
do (print s))
(loop for s being each external-symbols of "COMMON LISP"
do (print s))
(loop for s being each external-symbol in pack ;pack is a variable containing a package
do (print s))
산술 루프
(loop for i from 0 to 10
do (print i)) ; prints 0 1 2 3 4 5 6 7 8 9 10
(loop for i from 0 below 10
do (print i)) ; prints 0 1 2 3 4 5 6 7 8 9 10
(loop for i from 10 above 0
do (print i)) ; prints 10 9 8 7 6 5 4 3 2 1
(loop for i from 10 to 0
do (print i)) ; prints nothing
(loop for i from 10 downto 0
do (print i)) ; prints 10 9 8 7 6 5 4 3 2 1 0
(loop for i downfrom 10 to 0
do (print i)) ; same as above
(loop for i from 1 to 100 by 10
do (print i)) ; prints 1 11 21 31 41 51 61 71 81 91
(loop for i from 100 downto 0 by 10
do (print i)) ; prints 100 90 80 70 60 50 40 30 20 10 0
(loop for i from 1 to 10 by (1+ (random 3))
do (print i)) ; note that (random 3) is evaluated only once
(let ((step (random 3)))
(loop for i from 1 to 10 by (+ step 1)
do (print i))) ; equivalent to the above
(loop for i from 1 to 10
for j from 11 by 11
do (format t "~2d ~3d~%" i j)) ;prints 1 11\n2 22\n...10 110
FOR 문에서의 소멸
우리는 복합 객체의리스트를 제거 할 수있다.
CL-USER> (loop for (a . b) in '((1 . 2) (3 . 4) (5 . 6)) collect a)
(1 3 5)
CL-USER> (loop for (a . b) in '((1 . 2) (3 . 4) (5 . 6)) collect b)
(2 4 6)
CL-USER> (loop for (a b c) in '((1 2 3) (4 5 6) (7 8 9) (10 11 12)) collect b)
(2 5 8 11)
우리는 또한리스트 자체를 파기 할 수있다.
CL-USER> (loop for (a . b) on '(1 2 3 4 5 6) collect a)
(1 2 3 4 5 6)
CL-USER> (loop for (a . b) on '(1 2 3 4 5 6) collect b)
((2 3 4 5 6) (3 4 5 6) (4 5 6) (5 6) (6) NIL)
이것은 특정 요소 만 반복 할 때 유용합니다.
CL-USER> (loop for (a . b) on '(1 2 3 4 5 6) by #'cddr collect a)
(1 3 5)
CL-USER> (loop for (a . b) on '(1 2 3 4 5 6) by #'cdddr collect a)
(1 4)
NIL
을 사용하여 용어 무시 :
(loop for (a nil . b) in '((1 2 . 3) (4 5 . 6) (7 8 . 9))
collect (list a b)) ;=> ((1 3) (4 6) (7 9))
(loop for (a b) in '((1 2) (3 4) (5 6)) ;(a b) == (a b . nil)
collect (+ a b)) ;=> (3 7 11)
; iterating over a window in a list
(loop for (pre x post) on '(1 2 3 4 5 3 2 1 2 3 4)
for nth from 1
while (and x post) ; checks that we have three elements of the list
if (and (<= post x) (<= pre x)) collect (list :max x nth)
if (and (>= post x) (>= pre x)) collect (list :min x nth))
; The above collects local minima/maxima
표현식으로 LOOP
오늘날 사용되는 거의 모든 다른 프로그래밍 언어의 루프와 달리, Common Lisp의 LOOP
는 표현식으로 사용될 수 있습니다.
(let ((doubled (loop for x from 1 to 10
collect (* 2 x))))
doubled) ;; ==> (2 4 6 8 10 12 14 16 18 20)
(loop for x from 1 to 10 sum x)
MAXIMIZE
는 LOOP
가 평가 된 최대 값을 리턴하도록합니다. MINIMIZE
는 MAXIMIZE
의 반대입니다.
(loop repeat 100
for x = (random 1000)
maximize x)
COUNT
는 루프가 실행되는 동안 표현식이 NIL
이 아닌 것으로 평가 된 횟수를 알려줍니다.
(loop repeat 100
for x = (random 1000)
count (evenp x))
LOOP
에는 some
, every
및 notany
함수와 notany
기능이 있습니다.
(loop for ch across "foobar"
thereis (eq ch #\a))
(loop for x in '(a b c d e f 1)
always (symbolp x))
(loop for x in '(1 3 5 7)
never (evenp x))
... 시퀀스를 반복하는 것에 국한되지 않는다는 점을 제외하고는 :
(loop for value = (read *standard-input* nil :eof)
until (eq value :eof)
never (stringp value))
LOOP
값 생성 동사는 -ing 접미어로도 쓸 수 있습니다.
(loop repeat 100
for x = (random 1000)
minimizing x)
또한 이러한 동사에 의해 생성 된 값을 변수 ( LOOP
매크로에 의해 암시 적으로 생성됨)로 캡처 할 수 있으므로 한 번에 둘 이상의 값을 생성 할 수 있습니다.
(loop repeat 100
for x = (random 1000)
maximizing x into biggest
minimizing x into smallest
summing x into total
collecting x into xs
finally (return (values biggest smallest total xs)))
동일한 출력 값으로 collect
둘 이상의 collect
, count
등의 절을 가질 수 있습니다. 그들은 순차적으로 처형 될 것입니다.
다음은 ( assoc
과 함께 사용할 수있는) 연관 목록을 ( getf
와 함께 사용할 수있는) 속성 목록으로 변환합니다.
(loop for (key . value) in assoc-list
collect key
collect value)
이것이 더 나은 스타일이지만 :
(loop for (key . value) in assoc-list
append (list key value))
조건부로 실행되는 LOOP 절
LOOP
에는 절이 실행되는 방식을 제어 할 수있는 고유 한 IF
문이 있습니다.
(loop repeat 1000
for x = (random 100)
if (evenp x)
collect x into evens
else
collect x into odds
finally (return (values evens odds)))
IF 본문에 여러 절을 결합하려면 특수 구문이 필요합니다.
(loop repeat 1000
for x = (random 100)
if (evenp x)
collect x into evens
and do (format t "~a is even!~%" x)
else
collect x into odds
and count t into n-odds
finally (return (values evens odds n-odds)))
병렬 반복
LOOP
에서는 여러 FOR
절이 허용됩니다. 이 절의 첫 번째 항목이 완료되면 루프가 완료됩니다.
(loop for a in '(1 2 3 4 5)
for b in '(a b c)
collect (list a b))
;; Evaluates to: ((1 a) (2 b) (3 c))
루프를 계속해야하는지 결정하는 다른 절을 결합 할 수 있습니다.
(loop for a in '(1 2 3 4 5 6 7)
while (< a 4)
collect a)
;; Evaluates to: (1 2 3)
(loop for a in '(1 2 3 4 5 6 7)
while (< a 4)
repeat 1
collect a)
;; Evaluates to: (1)
응답이 알려지 자마자 반복을 차단하는 목록이 더 오래 있는지 확인하십시오.
(defun longerp (list-1 list-2)
(loop for cdr1 on list-1
for cdr2 on list-2
if (null cdr1) return nil
else if (null cdr2) return t
finally (return nil)))
목록 요소의 번호 매기기 :
(loop for item in '(a b c d e f g)
for x from 1
collect (cons x item))
;; Returns ((1 . a) (2 . b) (3 . c) (4 . d) (5 . e) (6 . f) (7 . g))
목록의 모든 숫자가 처음 100 개의 항목에 대해서만 짝수임을 확인하십시오.
(assert
(loop for number in list
repeat 100
always (evenp number)))
중첩 반복
특수 LOOP NAMED foo
구문을 사용하면 일찍 종료 할 수있는 루프를 만들 수 있습니다. exit는 return-from
사용하여 수행되며 중첩 루프 내에서 사용할 수 있습니다.
다음은 중첩 루프를 사용하여 2D 배열에서 복소수를 찾습니다.
(loop named top
for x from 0 below (array-dimension *array* 1)
do (loop for y from 0 below (array-dimension *array* 0))
for n = (aref *array* y x)
when (complexp n)
do (return-from top (values n x y))))
RETURN 절 대 RETURN 형식.
LOOP
내에서 어떤 식에서든 Common Lisp (return)
형식을 사용할 수 있습니다. 그러면 LOOP
형식이 return
할 값으로 즉시 평가됩니다.
LOOP
에는 거의 동일하게 작동하는 return
절이 있습니다. 유일한 차이점은 괄호로 묶지 않는 것입니다. 절은 LOOP
의 DSL 내에서 사용되는 반면 식은 표현식 내에서 사용됩니다.
(loop for x in list
do (if (listp x) ;; Non-barewords after DO are expressions
(return :x-has-a-list)))
;; Here, both the IF and the RETURN are clauses
(loop for x in list
if (listp x) return :x-has-a-list)
;; Evaluate the RETURN expression and assign it to X...
;; except RETURN jumps out of the loop before the assignment
;; happens.
(loop for x = (return :nothing-else-happens)
do (print :this-doesnt-print))
후 것은 finally
소위, 표현해야합니다 (return)
양식을 사용하지 않는해야 return
조항 :
(loop for n from 1 to 100
when (evenp n) collect n into evens
else collect n into odds
finally return (values evens odds)) ;; ERROR!
(loop for n from 1 to 100
when (evenp n) collect n into evens
else collect n into odds
finally (return (values evens odds))) ;; Correct usage.
목록 창의 반복
크기가 3 인 창에 대한 몇 가지 예는 다음과 같습니다.
;; Naïve attempt:
(loop for (first second third) on '(1 2 3 4 5)
do (print (* first second third)))
;; prints 6 24 60 then Errors on (* 4 5 NIL)
;; We will try again and put our attempt into a function
(defun loop-3-window1 (function list)
(loop for (first second third) on list
while (and second third)
do (funcall function first second third)))
(loop-3-window1 (lambda (a b c) (print (* a b c))) '(1 2 3 4 5))
;; prints 6 24 60 and returns NIL
(loop-3-window1 (lambda (a b c) (print (list a b c))) '(a b c d nil nil e f))
;; prints (a b c) (b c d) then returns NIL
;; A second attempt
(defun loop-3-window2 (function list)
(loop for x on list
while (nthcdr 2 x) ;checks if there are at least 3 elements
for (first second third) = x
do (funcall function first second third)))
(loop-3-window2 (lambda (a b c) (print (list a b c))) '(a b c d nil nil e f))
;; prints (a b c) (b c d) (c d nil) (c nil nil) (nil nil e) (nil e f)
;; A (possibly) more efficient function:
(defun loop-3-window2 (function list)
(let ((f0 (pop list))
(s0 (pop list)))
(loop for first = f0 then second
and second = s0 then third
and third in list
do (funcall function first second third))))
;; A more general function:
(defun loop-n-window (n function list)
(loop for x on list
while (nthcdr (1- n) x)
do (apply function (subseq x 0 n))))
;; With potentially efficient implementation:
(define-compiler-macro loop-n-window (n function list &whole w)
(if (typep n '(integer 1 #.call-arguments-limit))
(let ((vars (loop repeat n collect (gensym)))
(vars0 (loop repeat (1- n) collect (gensym)))
(lst (gensym)))
`(let ((,lst ,list))
(let ,(loop for v in vars0 collect `(,v (pop ,lst)))
(loop for
,@(loop for v0 in vars0 for (v vn) on vars
collect v collect '= collect v0 collect 'then collect vn
collect 'and)
,(car (last vars)) in ,lst
do ,(if (and (consp function) (eq 'function (car function))
w