수색…


바운드 루프

우리는 사용하여 작업을 여러 번 어떤 수를 반복 할 수 있습니다 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)

MAXIMIZELOOP 가 평가 된 최대 값을 리턴하도록합니다. MINIMIZEMAXIMIZE 의 반대입니다.

(loop repeat 100
      for x = (random 1000)
      maximize x)

COUNT 는 루프가 실행되는 동안 표현식이 NIL 이 아닌 것으로 평가 된 횟수를 알려줍니다.

(loop repeat 100
      for x = (random 1000)
      count (evenp x))

LOOP 에는 some , everynotany 함수와 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


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow