loop — 강력하고 간결한 범용 루프
loop — 강력하고 간결한 범용 루프
단순 반복은 dolist나 dotimes가 잘 해주지만, 순회하면서 값을 모으고(collect), 조건을 걸고(when), 세어야 할 때(count)는 각각을 따로 조합하기 번거로워요. loop는 이런 것들을 하나의 매크로 몸통에서 간결하게 표현해주는 강력한 반복 매크로예요.
본문
loop에는 크게 두 가지 형태가 있어요. **단순형(simple form)**은 조건 없이 몸통만 반복해요.
loop compound-form*
=> result*
**확장형(extended form)**이 진짜 힘이에요. 반복 변수, 종료 조건, 결과 누적 등을 선언적인 절(clause)들로 기술합니다.
loop [name-clause] {variable-clause}* {main-clause}*
=> result*
확장형이 받는 절 종류는 대략 이렇게 나뉘어요.
with— 반복 변수 초기화for/as— 반복 변수의 진행 방식(리스트 순회, 산술 진행 등)collect/append/nconc— 결과 리스트 누적sum/count/maximize/minimize— 수치 누적if/when/unless— 조건부 실행while/until/repeat/always/never/thereis— 종료·판정 조건initially/finally— 반복 전·후 처리return— 값 반환
먼저 단순형입니다. 실행기처럼 계속 입력을 받는 프로그램을 loop로 끝없이 돌린 뒤 return으로 빠져나가요.
(defun sqrt-advisor ()
(loop (format t "~&Number: ")
(let ((n (parse-integer (read-line) :junk-allowed t)))
(when (not n) (return))
(format t "~&The square root of ~D is ~D.~%" n (sqrt n)))))
=> SQRT-ADVISOR
(sqrt-advisor)
>> Number: 5<NEWLINE>
>> The square root of 5 is 2.236068.
>> Number: done<NEWLINE>
=> NIL
확장형을 쓰면 for로 반복 변수를, while로 종료 조건을, do로 몸통을 한 번에 묶을 수 있어요.
(defun square-advisor ()
(loop as n = (progn (format t "~&Number: ")
(parse-integer (read-line) :junk-allowed t))
while n
do (format t "~&The square of ~D is ~D.~%" n (* n n))))
누적 절의 맛은 이 예제에서 바로 드러나요. 1부터 10까지 홀수만 골라 리스트로 모으는데, when과 collect 두 절만으로 끝나요.
(loop for n from 1 to 10
when (oddp n)
collect n)
=> (1 3 5 7 9)
for 절이 다루는 진행 방식도 다양해요. 리스트의 각 원소를 돌려면 in, 리스트의 각 cons를 돌려면 on을 쓰고, 벡터를 훑을 땐 across, 해시 테이블의 키·값을 순회할 땐 being the hash-key / hash-value를 써요.
;; 리스트 순회
(loop for x in '(1 2 3) collect (* x x)) ; => (1 4 9)
;; 산술 진행
(loop for i from 1 to 5 sum i) ; => 15
;; 해시 테이블 순회
(loop for k being the hash-key of table
collect k)
함께 보기
do, dolist, dotimes, return, go, throw