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


답변:


169

원래 Lisp에는 어휘 변수가 없었으며 동적 변수 만있었습니다. 그리고 SETQ 또는 SETF는 없었으며 SET 기능 만있었습니다.

이제 다음과 같이 쓰여집니다 :

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

로 작성되었습니다 :

(set (quote *foo*) 42)

결국 SETQ (SET 인용)로 축약되었습니다.

(setq *foo* 42)

그런 다음 어휘 변수가 발생했고 SETQ도 할당에 사용되었으므로 SET를 둘러싼 단순한 래퍼가 아니 었습니다.

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

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의 후속 계승자들로부터 부팅 될 것입니다.


45
공통 Lisp에는 항상 어휘 변수가있었습니다. Common Lisp보다 먼저 Lisp에 대해 이야기하고 있어야합니다.
Rainer Joswig

4
SET 및 SETQ를 Common Lisp 후속 버전에서 부팅하려면 교체해야합니다. 높은 수준의 코드에서의 사용은 제한적이지만 낮은 수준의 코드 (예 : SETF가 구현 된 코드)에는 필요합니다.
Svante

13
자동차 기능으로 혼란 스러울 수있는 대신 '자동차'를 필드로 선택한 이유가 있습니까?
drudru

9
이 답변대한 setf의 스탠드에서 F를 무엇? (가) 주장 f사실을 의미 기능 이 아닌 필드 (또는 양식 필드의 setf의 몇 가지 의미가 동안이 정확하지 않을 수 있습니다처럼, 그 문제에 대한) 및 참조를 제공합니다 그래서, 그것은 보인다.
Joshua Taylor

1
요약 : set함수입니다. 따라서 환경을 모릅니다. set어휘 변수를 볼 수 없습니다. 인수의 기호 값만 설정할 수 있습니다. setq더 이상 "인용 설정"되지 않습니다. setq매크로가 아닌 특별한 형태 라는 사실이 그것을 보여줍니다.
KIM Taegyoon

142
(set ls '(1 2 3 4)) => Error - ls has no value

(set 'ls '(1 2 3 4)) => OK

(setq ls '(1 2 3 4)) => OK - make ls to (quote ls) and then have the usual set

(setf ls '(1 2 3 4)) => OK - same as setq so far BUT

(setf (car ls) 10) => Makes ls '(10 2 3 4) - not duplicated by setq/set

12
귀하의 답변이 가장 많이 투표 된 답변보다 더 명확하다고 생각합니다. 고마워
CDR

2
@Sourav, 예제 코드에서 문자 "l"(ell)을 변수 또는 기호로 사용하지 마십시오. 숫자 1과 시각적으로 구분하기가 너무 어렵습니다.
DavidBooth

아니요, 여전히 (car ls)가 l 값이 될 수있는 방법을 이해하지 못합니다. CLisp를 C로 변환하는 방법을 알고 있습니까? CLisp 인터프리터를 작성하는 방법은 무엇입니까?
49 분에서

@ user1952009 clisp는 하나의 공통 Lisp 구현입니다. 언어 자체를 참조하려면 가장 많이 사용되는 약어를 CL로 사용하십시오.
ssice

2
@ user1952009 후 (setq ls '(((1)))), (setf (car (car (car ls))) 5)값을 정의하기 때문에 문제가된다 ls상수 (C 문자열의 문자를 수정하는 등)이다. 후 (setq ls (list (list (list 1)))), (setf (car (car (car ls))) 5)단지처럼 작동 ls->val->val->val = 5C.에서
카일

21

setq단지처럼 set인용 된 첫 번째 인수와 - (set 'foo '(bar baz))처럼입니다 (setq foo '(bar baz)). setf반면에 실제로는 미묘합니다. "간접"과 같습니다. 나는 제안 http://www.nano.com/lisp/cmucl-tutorials/LISP-tutorial-16.html이 더 좋은 방법은 어떤 대답보다 그것을 이해하기 시작하는 여기에 제공 할 수 있습니다 ... 한마디로하지만, setf소요 첫 번째 인수를 "참조"로 사용하여 예를 들어 첫 번째 인수로 (aref myarray 3)작동 setf하여 배열 내부의 항목을 설정합니다.


1
setq 이름에 가장 적합합니다. 기억하기 쉽다. 감사.
CDR

17

당신이 사용할 수있는 setf대신에 setsetq아닌 그 반대 때문에이 setf변수가 개별 요소가있는 경우에도 변수의 개별 요소의 값을 설정할 수 있습니다. 아래의 사례를 참조하십시오.

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

(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)

setf목록의 멤버를 foo새로운 값 으로 설정하는 기능이 추가되었습니다 .

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

(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))

13

저수준 구조를 생각 SET하고 가질 수 있습니다 SETQ.

  • SET 기호 값을 설정할 수 있습니다.

  • SETQ 변수 값을 설정할 수 있습니다.

그런 다음 SETF매크로는 심볼, 변수, 배열 요소, 인스턴스 슬롯 등 다양한 설정 항목을 제공합니다.

기호와 변수의 경우 와 SETF로 확장되는 것처럼 생각할 수 있습니다 .SETSETQ

* (macroexpand '(setf (symbol-value 'a) 10))

(SET 'A 10)


* (macroexpand '(setf a 10))         

(SETQ A 10)

그래서 SETSETQ의 기능의 일부 구현하는 데 사용됩니다 SETF더 일반적인 구조입니다. 다른 답변 중 일부는 심볼 매크로를 고려할 때 약간 더 복잡한 이야기를 알려줍니다.


4

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))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.