common-lisp - 설치 - 커먼 리스프




Common Lisp에서`set`,`setq`,`setf`의 차이점은 무엇입니까? (4)

Common Lisp에서 "set", "setq"및 "setf"의 차이점은 무엇입니까?


setf가 첫 번째 인수로 전달 된 내용에 따라 특정 함수를 호출하는 매크로 인 이전 대답을 추가하고 싶습니다. setf의 매크로 확장 결과를 다른 유형의 인수와 비교하십시오.

(macroexpand '(setf a 1))

(macroexpand '(setf (car (list 3 2 1)) 1))

(macroexpand '(setf (aref #(3 2 1) 0) 1))

어떤 타입의 인자들에 대해 "setf function"이 호출 될 것입니다 :

(defstruct strct field)
(macroexpand '(setf (strct-field (make-strct)) 1))

원래 Lisp에는 어휘 변수가 없었습니다 - 동적 변수 만있었습니다. 그리고 SETQ 나 SETF도없고 SET 함수 만있었습니다.

현재 다음과 같이 작성된 내용 :

(setf (symbol-value '*foo*) 42)

다음과 같이 작성되었습니다.

(set (quote *foo*) 42)

결국 약어가 SETQ (SET Quoted)로 축약되었습니다.

(setq *foo* 42)

그런데 어휘 변수가 생겼고 SETQ가 할당에 사용되었습니다. 그래서 더 이상 SET 주위의 간단한 래퍼가 아닙니다.

나중에 누군가가 SETF (SET Field)를 다른 언어의 l- 값을 반영하기 위해 데이터 구조에 값을 할당하는 일반적인 방법으로 발명했습니다.

x.car := 42;

다음과 같이 작성됩니다.

(setf (car x) 42)

대칭 및 일반성을 위해 SETF는 SETQ의 기능도 제공했습니다. 이 시점에서 SETQ는 낮은 수준의 프리미티브이고 SETF는 높은 수준의 작업이라고 말할 수 있습니다.

그런 다음 심볼 매크로가 발생했습니다. 그 심볼 매크로가 투명하게 작동 할 수 있도록 할당 된 "변수"가 실제로 심볼 매크로 인 경우 SETQ가 SETF와 같이 작동해야한다는 것을 깨달았습니다.

(defvar *hidden* (cons 42 42))
(define-symbol-macro foo (car *hidden*))

foo => 42

(setq foo 13)

foo => 13

*hidden* => (13 . 42)

그래서 우리는 현재에 도착합니다 : SET와 SETQ는 더 오래된 방언의 유적을 싫어하고 아마도 Common Lisp의 후계자로부터 부팅 될 것입니다.


setfsetf 또는 setq 대신 setf 를 사용할 수 있지만 setf 는 변수에 개별 요소가있는 경우 변수의 개별 요소 값을 설정할 수 있기 때문에 setf 사용할 수 있습니다. 아래 exaples를 참조하십시오 :

네 개의 예제 모두 foo라는 변수에 목록 (1, 2, 3)을 할당합니다.

(set (quote foo) (list 1 2 3))    ;foo => (1 2 3)
(1 2 3)

(set 'foo '(1 2 3))   ;foo => (1 2 3) same function, simpler expression
(1 2 3)

(setq foo '(1 2 3))   ;foo => (1 2 3) similar function, different syntax
(1 2 3)

(setf foo '(1 2 3))   ;foo => (1 2 3) more capable function
(1 2 3)

setffoo 에있는리스트의 멤버를 새로운 값으로 설정하는 추가 된 기능을 가지고 있습니다.

foo                   ;foo => (1 2 3) as defined above
(1 2 3)

(car foo)             ;the first item in foo is 1
1

(setf (car foo) 4)    ;set or setq will fail since (car foo) is not a symbol
4

foo                   ;the fist item in foo was set to 4 by setf
(4 2 3)

그러나 foo 내의 단일 항목을 reprents하는 기호 매크로를 정의 할 수 있습니다

(define-symbol-macro foo-car (car foo))    ; assumes FOO => (1 2 3)
FOO-CAR

foo-car               ;foo-car is now a symbol for the 1st item in foo
1

(setq foo-car 4)      ;set or setq can set the symbol foo-car 
4

foo                   ;Lisp macros are so cool
(4 2 3)

변수를 아직 정의하지 않았 으면 defvar 를 사용할 수 있으며 나중에 코드에서 값을 제공하고 싶지는 않습니다.

(defvar foo2)
(define-symbol-macro foo-car (car foo2))

setq 는 따옴표로 묶인 첫 번째 arg - (set 'foo '(bar baz)) 와 마찬가지로 (setq foo '(bar baz)) 와 같습니다. 다른 한편, setf 는 실제로 미묘합니다. 이것은 "우회"와 같습니다. 필자는 http://www.n-a-n-o.com/lisp/cmucl-tutorials/LISP-tutorial-16.html 을 더 나은 방법으로 제안하여 모든 대답보다 더 쉽게 이해할 수있는 방법을 제안합니다 ... 간단히 말해 setf 는 첫 번째 인수는 "참조"로, 예를 들어 (aref myarray 3) 배열 내에서 항목을 설정하기 위해 (첫 번째 인수는 setf ) 작동합니다.