dotimes — 정해진 횟수만큼 반복

dotimes — 정해진 횟수만큼 반복

리스트를 순회할 땐 dolist, 그리고 몇 번 반복할지가 미리 정해져 있을 때는 dotimes가 어울려요. "세 번만 돌려" 같은 정해진 횟수의 반복은 dotimes가 훨씬 간결하게 표현해 줘요.

출처: CLHS 공식 문서 - DOTIMES

본문

dotimes는 0부터 시작하는 정수들을 차례로 var에 묶어가며 본문을 실행하는 반복 매크로예요. 몇 번 돌지가 count-form에 담겨 있어요.

dotimes (var count-form [result-form]) declaration* {tag | statement}*
=> result*

count-form을 평가한 값이 0이나 음수면 본문은 아예 실행되지 않아요. 그렇지 않으면 count-form의 값보다 작은 정수 0, 1, 2, ...var에 묶어 각각 본문을 실행해요. 반복이 끝나면 result-form을 평가하는데, 이때 var본문이 실제로 실행된 횟수로 묶여 있어요.

(dotimes (temp-one 10 temp-one)) ; =>  10

본문이 비어 있어도 var는 10번 묶였으니, result-form으로 temp-one을 돌려주면 10이 나와요. 본문에서 횟수를 직접 세는 것도 해요요.

(setq temp-two 0)  ; =>  0
(dotimes (temp-one 10 t) (incf temp-two))
=>  T
temp-two  ; =>  10

dotimes는 문자열을 처리할 때도 유용해요. 인덱스로 문자를 하나씩 꺼내 비교할 수 있죠. 아래는 부분 문자열이 회문(palindrome)인지 검사하는 함수예요.

(dotimes (k (floor (- end start) 2) t)
  (unless (char-equal (char string (+ start k))
                      (char string (- end k 1)))
    (return nil)))

(palindromep "Able was I ere I saw Elba")  ; =>  T
(palindromep "A man, a plan, a canal--Panama!")  ; =>  NIL

구두점을 지우고 비교하면 아래처럼 성립해요.

(palindromep
  (remove-if-not #'alpha-char-p
                 "A man, a plan, a canal--Panama!"))
=>  T

dolist와 마찬가지로 dotimes 폼 전체는 nil이라는 암묵적 블록으로 감싸여 있고, 본문은 암묵적 tagbody예요. 그래서 return으로 즉시 빠져나가거나 go로 특정 위치로 점프할 수 있어요. var의 묶음 범위는 count-form을 포함하지 않고, result-form은 포함해요.

함께 보기

do, dolist, tagbody