수색…


그룹화는 언제 필요합니까?

Common Lisp의 일부 장소에서는 일련의 양식이 순서대로 평가됩니다. 예를 들어, defun 또는 lambda 의 본문이나 점선 의 본문에서. 이 경우 여러 양식을 순서대로 작성하면 예상대로 작동합니다. 그러나 if 표현식의 thenelse 부분과 같은 몇 군데에서는 단 하나의 형식 만 허용됩니다. 물론, 그 장소에서 여러 표현식을 실제로 평가할 수도 있습니다. 이러한 상황에서 암묵적인 명시적인 그룹화 형식이 필요합니다.

예측

범용 특수 연산자 progn 은 0 개 이상의 형식을 평가하는 데 사용됩니다. 마지막 형식의 값이 반환됩니다. 예를 들어, 다음에서 (print 'hello) 가 평가되고 (그 결과는 무시된다), 42 가 평가되고 그 결과 ( 42 )가 반환된다 :

(progn 
  (print 'hello)
  42)
;=> 42

progn에 형식이 없으면 nil 이 반환됩니다.

(progn)
;=> NIL

일련의 양식을 그룹화하는 것 외에도 prognprogn 양식이 최상위 양식 인 경우 모든 양식이 최상위 양식 으로 처리된다는 중요한 특성이 있습니다. 이것은 최상위 양식으로 모두 처리해야하는 여러 양식으로 확장되는 매크로를 작성할 때 중요 할 수 있습니다.

Progn 은 마지막 형식의 모든 값을 반환한다는 점에서 가치가 있습니다. 예를 들어,

(progn
  (print 'hello)
  (values 1 2 3))
;;=> 1, 2, 3

대조적으로, 일부 그룹화 표현식은 결과 생성 양식의 기본 값만 리턴합니다.

암시 적 예측

어떤 형태는 암묵적인 예언 을 사용하여 행동을 묘사합니다. 예를 들어, 폼의 경우 본질적으로 일방적 인 whenunless 매크로는 암시적인 progn의 관점에서 동작을 설명합니다. 이것은 다음과 같은 형식을 의미합니다.

(when (foo-p foo)
  form1
  form2)

(foo-p foo) 조건이 참이면 form1form2progn에 포함 된 것처럼 그룹화됩니다. when 매크로의 확장은 본질적으로 다음과 같습니다.

(if (foo-p foo)
  (progn
    form1
    form2)
  nil)

Prog1 및 Prog2

종종 여러 표현식을 평가하고 마지막 표현식이 아닌 첫 번째 또는 두 번째 형식의 결과를 반환하는 것이 도움이됩니다. let 및을 사용하여 쉽게 수행 할 수 있습니다 . 예를 들면 다음과 같습니다.

(let ((form1-result form1))
  form2
  form3
  ;; ...
  form-n-1
  form-n
  form1-result)

이 형식은 일부 응용 프로그램에서 일반적이므로 Common Lisp에는 progn 과 같은 prog1prog2 가 포함되지만 각각 첫 번째와 두 번째 형식의 결과가 반환됩니다. 예를 들면 :

(prog1
  42
  (print 'hello)
  (print 'goodbye))
;; => 42
(prog2
  (print 'hello)
  42
  (print 'goodbye))
;; => 42

PROG1 / PROG2progn 간의 중요한 차이점은, 그러나, PROG1PROG2에만 제 1 및 제 2 형태의 기본 값을 반환하는 반면 progn가 최종 형태의 모든 값을 반환한다. 예를 들면 :

(progn
  (print 'hello)
  (values 1 2 3))
;;=> 1, 2, 3

(prog1
  (values 1 2 3)
  (print 'hello))
;;=> 1              ; not 1, 2, 3

prog1 스타일 평가를 사용하는 여러 값의 경우 대신 multiple-value-prog1을 사용하십시오. 비슷한 다중 가치 prog2 는 없지만 필요한 경우 구현하기가 어렵지 않습니다.

블록

특수 연산자 블록 은 암시 적 progn 과 같은 여러 Lisp 양식을 그룹화 할 수 있으며 블록의 이름 을 지정하기 위해 이름을 사용합니다. 블록 내의 양식을 평가할 때 특수 연산자 return-from 을 사용하여 블록을 떠날 수 있습니다. 예를 들면 :

(block foo
  (print 'hello)     ; evaluated
  (return-from foo)
  (print 'goodbye))  ; not evaluated
;;=> NIL

반환 값은 반환 값과 함께 제공 될 수도 있습니다.

(block foo
  (print 'hello)     ; evaluated
  (return-from foo 42)
  (print 'goodbye))  ; not evaluated
;;=> 42

명명 된 블록은 코드 덩어리가 의미있는 이름을 가질 때 또는 블록이 중첩 될 때 유용합니다. 어떤 맥락에서는 블록에서 일찍 돌아올 수있는 능력 만 중요합니다. 이 경우 블록 이름으로 nil 을 사용하여 리턴 할 수 있습니다. return 은 블록 이름이 항상 nil 이라는 점만 제외하면 return-from 과 같습니다.

참고 : 동봉 된 양식은 최상위 양식이 아닙니다. 이것은 progn 과 다르다. 여기서 둘러싸인 형태의 최상위 progn 형식은 여전히 최상위 형태로 간주된다.

태그 바디

그룹 폼에서 많은 제어를 위해 tagbody 특수 연산자가 매우 유용 할 수 있습니다. tagbody 폼 내부의 폼은 go 태그 (그냥 기호 또는 정수) 또는 실행할 폼입니다. tagbody 내에서 go 특수 연산자는 실행을 새 위치로 전송하는 데 사용됩니다. 이러한 유형의 프로그래밍은 임의의 실행 경로를 허용하기 때문에 상당히 낮은 수준으로 간주 될 수 있습니다. 다음은 for-loop을 tagbody 로 구현했을 때의 모습을 보여주는 자세한 예입니다.

(let (x)               ; for (x = 0; x < 5; x++) { print(hello); }
  (tagbody
     (setq x 0)
   prologue
     (unless (< x 5)
       (go end))
   begin
     (print (list 'hello x))
   epilogue
     (incf x)
     (go prologue)
   end))

tagbodygo 는 일반적으로 "GOTO가 유해하다고 생각하기"때문에 일반적으로 사용되지 않지만 상태 시스템과 같은 복잡한 제어 구조를 구현할 때는 도움이 될 수 있습니다. 많은 반복 구조 또한 암시적인 태그 바디 로 확장됩니다. 예를 들어, 점들 (dotimes )의 본문은 일련의 태그 및 양식으로 지정됩니다.

어떤 양식을 사용해야합니까?

그룹화와 관련된 양식으로 확장되는 매크로를 작성할 때 어떤 그룹화 구성을 확장 할 것인지 고려하는 것이 좋습니다.

정의 스타일 형태의 경우, 예를 들면, 정의 - 위젯 등 일반적으로 최상위 형태로 나타납니다 매크로, 그리고 여러 defun는 s의 defstruct들, 보통 그 자식 폼이 있도록하는 progn를 사용하는 것이 합리적이다 최상위 양식으로 처리됩니다. 반복 양식의 경우 암시적인 태그 바디 가 더 일반적입니다.

예를 들어,의 몸 dotimes , DOLIST , 그리고 어떻게 각각 암시 tagbody로 확장합니다.

코드의 명명 된 "덩어리"를 정의하는 양식의 경우 암시 적 블록 이 유용 할 때가 많습니다. 예를 들어, defun 본문은 암시 적 progn 내부에 있지만 암시 적 progn 은 함수 이름을 공유하는 블록 내에 있습니다. 즉, return-from 을 사용하여 함수에서 빠져 나올 수 있습니다. 그런 광고문



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