Lisp에서 '(또는 따옴표)를 언제 사용합니까?


114

Lisp 입문 책의 주요 부분을 살펴본 후에도 특수 연산자 (quote)(또는 동등한 ') 함수가 하는 일을 여전히 이해할 수 없었지만 이것은 내가 본 Lisp 코드 전체에 걸쳐 있습니다.

그것은 무엇을합니까?

답변:


178

단답형 기본 평가 규칙을 무시하고 표현식 (기호 또는 s-exp)을 평가 하지 않고 입력 한대로 정확히 함수에 전달합니다.

긴 답변 : 기본 평가 규칙

정규 (나중에 설명하겠습니다) 함수가 호출되면 전달 된 모든 인수가 평가됩니다. 이것은 다음과 같이 작성할 수 있음을 의미합니다.

(* (+ a 2)
   3)

설정에 어떤 평가하여 (+ a 2)평가하여, a심볼의 값과 2 a의 현재 변수 결합 세트에서 조회하고 대체된다. Say a는 현재 값 3에 바인딩되어 있습니다.

(let ((a 3))
  (* (+ a 2)
     3))

우리는 (+ 3 2), +를 3과 2에서 호출하여 5를 산출합니다. 원래 형식은 이제 (* 5 3)15를 산출합니다.

quote이미 설명하십시오 !

좋구나. 위에서 볼 수 있듯이 함수에 대한 모든 인수가 평가되므로 값이 아닌 기호 를 전달 a하려는 경우 평가하고 싶지 않습니다. Lisp 기호는 값으로 두 배가 될 수 있으며 다른 언어에서 해시 테이블에 대한 키와 같은 문자열을 사용한 마커도 사용할 수 있습니다.

이것이 quote들어오는 곳 입니다. Python 응용 프로그램에서 리소스 할당을 플로팅하려는 대신 Lisp에서 플로팅을 수행한다고 가정 해 보겠습니다. Python 앱이 다음과 같은 작업을 수행하도록합니다.

print("'(")
while allocating:
    if random.random() > 0.5:
        print(f"(allocate {random.randint(0, 20)})")
    else:
        print(f"(free {random.randint(0, 20)})")
    ...
print(")")

다음과 같은 출력을 제공합니다 (약간 예쁘게 표시됨).

'((allocate 3)
  (allocate 7)
  (free 14)
  (allocate 19)
  ...)

quote기본 규칙이 적용되지 않게하는 원인 ( "틱") 에 대해 내가 말한 것을 기억 하십니까? 좋은. 어떤 다른 일이 일어날 것이 값이다 allocate하고 free고개 있으며, 우리는 그것을 원하지 않는다. Lisp에서 다음을 수행하고 싶습니다.

(dolist (entry allocation-log)
  (case (first entry)
    (allocate (plot-allocation (second entry)))
    (free (plot-free (second entry)))))

위에 제공된 데이터에 대해 다음과 같은 일련의 함수 호출이 만들어졌습니다.

(plot-allocation 3)
(plot-allocation 7)
(plot-free 14)
(plot-allocation 19)

하지만 어떨까요 list?

음, 때로는 않습니다 인수를 평가합니다. 숫자와 문자열을 조작하고 결과 목록을 반환하는 멋진 함수가 있다고 가정 해 보겠습니다. 잘못된 시작을합시다 :

(defun mess-with (number string)
  '(value-of-number (1+ number) something-with-string (length string)))

Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER (1+ NUMBER) SOMETHING-WITH-STRING (LENGTH STRING))

야! 그것은 우리가 원하는 것이 아닙니다. 우리는 일부 주장 을 선택적으로 평가하고 나머지는 상징으로 남겨두고 싶습니다 . # 2를 시도하십시오!

(defun mess-with (number string)
  (list 'value-of-number (1+ number) 'something-with-string (length string)))

Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER 21 SOMETHING-WITH-STRING 3)

다만 quote, 그러나backquote

훨씬 낫다! 덧붙여서,이 패턴은 (대부분) 매크로에서 너무나 흔해서 그렇게하기위한 특별한 구문이 있습니다. 역 따옴표 :

(defun mess-with (number string)
  `(value-of-number ,(1+ number) something-with-string ,(length string)))

를 사용하는 것과 비슷 quote하지만 쉼표로 접두사를 붙여 일부 인수를 명시 적으로 평가할 수있는 옵션이 있습니다. 결과는를 사용하는 것과 동일 list하지만 매크로에서 코드를 생성하는 경우 반환 된 코드의 작은 부분 만 평가하기를 원하므로 역 따옴표가 더 적합합니다. 짧은 목록의 list경우 더 읽기 쉽습니다.

이봐, 당신은 잊어 버렸습니다 quote!

그래서 이것이 우리를 어디로 떠나는가? 아 맞다, quote실제로 무엇을 하는가? 단순히 평가되지 않은 인수를 반환합니다! 처음에 정규 함수에 대해 말한 것을 기억하십니까? 일부 연산자 / 함수 는 인수를 평가 하지 않아도됩니다 . IF와 같은-그렇지 않은 경우 else 분기가 평가되는 것을 원하지 않습니까? 소위 특수 연산자 는 매크로와 함께 작동합니다. 특수 연산자는 또한 언어의 "공리"(최소한의 규칙 집합)이며 다른 방식으로 결합하여 나머지 Lisp를 구현할 수 있습니다.

quote하지만로 돌아 가기 :

Lisp> (quote spiffy-symbol)
SPIFFY-SYMBOL

Lisp> 'spiffy-symbol ; ' is just a shorthand ("reader macro"), as shown above
SPIFFY-SYMBOL

(Steel-Bank Common Lisp에서) 비교 :

Lisp> spiffy-symbol
debugger invoked on a UNBOUND-VARIABLE in thread #<THREAD "initial thread" RUNNING   {A69F6A9}>:
  The variable SPIFFY-SYMBOL is unbound.

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [ABORT] Exit debugger, returning to top level.

(SB-INT:SIMPLE-EVAL-IN-LEXENV SPIFFY-SYMBOL #<NULL-LEXENV>)
0] 

spiffy-symbol현재 범위에 없기 때문에 !

합산

quote, backquote(쉼표 포함) 및 list목록을 만드는 데 사용하는 도구 중 일부입니다. 값 목록 일뿐만 아니라 보시다시피 경량 (를 정의 할 필요가 없음 struct) 데이터 구조 로 사용할 수 있습니다 !

더 많은 것을 배우고 싶다면, 이미 프로그래밍에 관심이 있다면 Peter Seibel의 책 Practical Common Lisp 를 추천합니다. 결국 Lisp 여정에서 패키지도 사용하기 시작합니다. Ron Garret의 The Idiot 's Guide to Common Lisp Packages 는 이에 대한 좋은 설명을 제공합니다.

해피 해킹!


내 emacs에서 SBCL이 설정되어 있고` 'this'is 'true`를 입력하면 출력에서 ​​마지막 즉 TRUE 만 반환합니다. portacle에서도 동일한 결과를 얻습니다
Totoro

@Totoro 함수 또는 lisp의 여러 명령문의 반환 값은 마지막 표현식이므로 실제로 this, then is, then을 반환 true하지만 마지막 반환 된 것만 볼 수 있습니다. (이것은 사실이며 사실은 별도의 진술입니다)
Wezl

52

"나를 평가하지 마십시오"라고되어 있습니다. 예를 들어 목록을 코드가 아닌 데이터로 사용하려면 그 앞에 따옴표를 붙입니다. 예를 들면

(print '(+ 3 4))"(+ 3 4)"를 (print (+ 3 4))인쇄하고 "7"을 인쇄합니다.


예를 들어 unquote명령이 있습니까?
Lime

3
@William Lisps라는 편리한 기능을 가지고 eval: (print (eval '(+ 3 4))). 이것이 Lisps를 훌륭하게 만드는 이유입니다. 목록은 코드이고 코드는 목록이므로 Lisp 프로그램은 스스로 조작 할 수 있습니다.
darkfeline 2015 년

18

다른 사람들이이 질문에 훌륭하게 대답했고 Matthias Benkard는 훌륭한 경고를 내놓았습니다.

나중에 수정할 목록을 만들 때 견적을 사용하지 마십시오. 스펙을 통해 컴파일러는 인용 된 목록을 상수로 처리 할 수 ​​있습니다. 종종 컴파일러는 메모리에 단일 값을 만든 다음 상수가 나타나는 모든 위치에서 해당 단일 값을 참조하여 상수를 최적화합니다. 즉, 상수를 익명의 전역 변수처럼 취급 할 수 있습니다.

이것은 명백한 문제를 일으킬 수 있습니다. 상수를 수정하면 완전히 관련이없는 코드에서 동일한 상수의 다른 사용을 매우 잘 수정할 수 있습니다. 예를 들어, 일부 함수에서 일부 변수를 '(1 1)과 비교하고 완전히 다른 함수에서'(1 1)로 목록을 시작한 다음 더 많은 항목을 추가 할 수 있습니다. 이 함수를 실행하면 첫 번째 함수가 더 이상 올바르게 일치하지 않는 것을 발견 할 수 있습니다. 이제 두 번째 함수가 반환 한 변수 인 '(1 1 2 3 5 8 13)과 비교하려고하기 때문입니다. 이 두 함수는 완전히 관련이 없지만 상수 사용으로 인해 서로 영향을 미칩니다. 완전히 정상적인 목록 반복이 갑자기 무한 반복되는 것처럼 미친 나쁜 효과조차도 발생할 수 있습니다.

비교와 같이 상수 목록이 필요한 경우 따옴표를 사용하십시오. 결과를 수정할 때 목록을 사용하십시오.


따라서 (list (+ 1 2)) 대부분의 시간 을 사용해야하는 것 같습니다 . 그렇다면 (+ 1 2)그러한 예제 내부 의 평가를 어떻게 방지 합니까? 있습니까 unquote명령은?
Lime

1
과 동등 '((3))하거나 동등한 것을 원하십니까 '((+ 1 2))? 후자의 경우 더 많이 사용해야합니다 list: (list (list '+ 1 2)). 또는 당신은 동등한 원한다면 '(+ 1 2)단지를 (list '+ 1 2). 그리고 목록을 수정하지 않는 경우 따옴표를 사용 '(+ 1 2)해도됩니다. 단순히 비교 하는 경우 에는 아무 문제가 없습니다 .
Xanthir

1
인용 된 목록이 상수로 취급되어야하는 곳을 참조 해 주시겠습니까?
Lime

HyperSpec clhs.lisp.se/Body/s_quote.htm 은 인용 된 개체가 파괴적으로 수정되면 동작이 정의되지 않는다고 말합니다. 이것은 impls가 값을 원자 값으로 취급 할 수 있도록 함을 암시합니다.
Xanthir 2011

14

이 질문에 대한 한 가지 대답은 QUOTE가 "목록 데이터 구조를 생성"한다는 것입니다. 이것은 옳지 않습니다. QUOTE는 이것보다 더 근본적입니다. 사실, QUOTE는 사소한 연산자입니다. 그 목적은 어떤 일도 발생 하지 않도록 방지하는 것입니다. 특히 아무것도 생성하지 않습니다.

(QUOTE X)는 기본적으로 "아무것도하지 말고 X 만주세요"라고 말합니다. X는 (QUOTE (ABC))의 목록이나 (QUOTE FOO)의 기호 일 필요는 없습니다. 어떤 객체라도 될 수 있습니다. 실제로 (LIST 'QUOTE SOME-OBJECT)에 의해 생성 된 목록을 평가 한 결과는 항상 SOME-OBJECT를 반환합니다.

이제 (QUOTE (ABC))가 요소가 A, B, C 인 목록을 만든 것처럼 보이는 이유는 이러한 목록이 실제로 반환되는 것입니다. 그러나 QUOTE 양식이 평가 될 때 목록은 일반적으로 코드를 실행하기 전에 로더 또는 리더에 의해 생성 된 한동안 (QUOTE 양식의 구성 요소로!) 이미 존재했습니다.

초보자를 상당히 자주 끌어들이는 경향이있는 한 가지 의미는 QUOTE 양식에서 반환 된 목록을 수정하는 것이 현명하지 않다는 것입니다. QUOTE가 반환하는 데이터는 모든 의도와 목적을 위해 실행중인 코드의 일부로 간주되므로 읽기 전용으로 처리해야합니다!


11

인용 부호는 양식의 실행 또는 평가를 방지하여 대신 데이터로 변환합니다. 일반적으로 데이터를 평가하여 실행할 수 있습니다.

quote는 목록 데이터 구조를 생성합니다. 예를 들어 다음은 동일합니다.

(quote a)
'a

또한 목록 (또는 트리)을 만드는 데 사용할 수 있습니다.

(quote (1 2 3))
'(1 2 3)

Practical Common Lisp (온라인으로 읽을 수 있음) 와 같은 lisp에 대한 소개 책을 얻는 것이 가장 좋습니다 .


3

Emacs Lisp에서 :

무엇을 인용 할 수 있습니까?

목록 및 기호.

숫자를 인용하면 숫자 자체로 평가 '5됩니다 5.

목록을 인용하면 어떻게됩니까?

예를 들면 :

'(one two) 평가하다

(list 'one 'two) 평가하는

(list (intern "one") (intern ("two"))).

(intern "one")"one"이라는 심볼을 생성하고 "중앙"해시 맵에 저장하므로 언제든지 'one이름 "one"이 지정된 심볼 이 해당 중앙 해시 맵에서 조회됩니다.

그러나 상징은 무엇입니까?

예를 들어, OO 언어 (Java / Javascript / Python)에서 심볼은 위와 name같은 심볼의 이름 인 필드 가있는 객체로 표현 될 수 있으며 "one"데이터 및 / 또는 코드가이 객체와 연관 될 수 있습니다.

따라서 Python의 기호는 다음과 같이 구현 될 수 있습니다.

class Symbol:
   def __init__(self,name,code,value):
       self.name=name
       self.code=code
       self.value=value

예를 들어 Emacs Lisp에서 심볼은 1) 연관된 데이터와 (동시에-동일한 심볼에 대해) 2) 연관된 코드를 가질 수 있습니다. 컨텍스트에 따라 데이터 또는 코드가 호출됩니다.

예를 들어 Elisp에서 :

(progn
  (fset 'add '+ )
  (set 'add 2)
  (add add add)
)

로 평가됩니다 4.

다음 (add add add)과 같이 평가되기 때문입니다.

(add add add)
(+ add add)
(+ 2 add)
(+ 2 2)
4

예를 들어 Symbol위의 Python에서 정의한 클래스를 사용하면 이 addELisp-Symbol은 Python에서 Symbol("add",(lambda x,y: x+y),2).

기호와 따옴표를 설명 해준 IRC #emacs의 사람들에게 감사드립니다.


2

인수 값을 전달하는 대신 인수 자체를 전달하려면 따옴표를 사용합니다. 이것은 대부분 C 프로그래밍 언어에서 사용할 수없는 목록, 쌍 및 원자를 사용하는 동안 전달되는 절차와 관련이 있습니다 (대부분의 사람들은 C 프로그래밍을 사용하여 프로그래밍을 시작하므로 혼란스러워집니다). 이것은 lisp의 방언 인 Scheme 프로그래밍 언어의 코드입니다. 이 코드를 이해할 수있을 것 같습니다.

(define atom?              ; defining a procedure atom?
  (lambda (x)              ; which as one argument x
(and (not (null? x)) (not(pair? x) )))) ; checks if the argument is atom or not
(atom? '(a b c)) ; since it is a list it is false #f

마지막 줄 (atom? 'abc)은 abc가 원자인지 아닌지 확인하는 프로 시저에있는 그대로 abc를 전달하지만 (atom? abc)를 전달하면 abc 값을 확인하고 값을 전달합니다. 그것. 그 이후로 우리는 가치를 제공하지 않았습니다.


1

Quote는 인수의 내부 표현을 반환합니다. 인용문 이하지 않는 것에 대한 너무 많은 설명을 훑어 본 후 , 전구가 켜진 시점입니다. REPL이 함수 이름을 인용했을 때 대문자로 변환하지 않았다면 나에게 알려지지 않았을 것입니다.

그래서. 일반 Lisp 함수는 인수를 내부 표현으로 변환하고 인수를 평가하고 함수를 적용합니다. Quote는 인수를 내부 표현으로 변환하고 반환합니다. 기술적으로는 "평가하지 마십시오"라고 말하는 것이 옳습니다. 그러나 그것이 무엇을했는지 이해하려고 할 때 그것이 무엇을하지 않는지 말하면 실망 스러웠습니다. 내 토스터는 Lisp 기능도 평가하지 않습니다. 하지만 그것은 토스터가하는 일을 설명하는 방법이 아닙니다.


1

Anoter 짧은 답변 :

quote그것을 평가하지 않고 수단과 역 인용 부호는 인용하지만 휴가입니다 다시 문 .

좋은 참조 :

Emacs Lisp 참조 설명서는이를 매우 명확하게합니다.

9.3 인용

특수 형식 quote는 평가하지 않고 작성된대로 단일 인수를 반환합니다. 이것은 프로그램에서 자체 평가 개체가 아닌 상수 기호 및 목록을 포함하는 방법을 제공합니다. (숫자, 문자열 및 벡터와 같은 자체 평가 개체를 인용 할 필요가 없습니다.)

특수 양식 : 견적 객체

This special form returns object, without evaluating it. 

따옴표는 프로그램에서 자주 사용되기 때문에 Lisp는 편리한 읽기 구문을 제공합니다. 아포스트로피 문자 ( '' ')와 Lisp 개체 (읽기 구문)는 첫 번째 요소가 따옴표이고 두 번째 요소가 개체 인 목록으로 확장됩니다. 따라서 읽기 구문 'x는 (따옴표 x)의 약어입니다.

다음은 따옴표를 사용하는 표현식의 몇 가지 예입니다.

(quote (+ 1 2))
      (+ 1 2)

(quote foo)
      foo

'foo
      foo

''foo
      (quote foo)

'(quote foo)
      (quote foo)

9.4 백 쿼트

역 따옴표 구조를 사용하면 목록을 인용 할 수 있지만 해당 목록의 요소를 선택적으로 평가할 수 있습니다. 가장 간단한 경우에는 특수 양식 인용과 동일합니다 (이전 섹션에서 설명했습니다. 인용 참조). 예를 들어 다음 두 형식은 동일한 결과를 생성합니다.

`(a list of (+ 2 3) elements)
      (a list of (+ 2 3) elements)

'(a list of (+ 2 3) elements)
      (a list of (+ 2 3) elements)

역 따옴표 인수 내부의 특수 마커 ','는 상수가 아닌 값을 나타냅니다. Emacs Lisp 평가자는 ','의 인수를 평가하고 값을 목록 구조에 넣습니다.

`(a list of ,(+ 2 3) elements)
      (a list of 5 elements)

목록 구조의 더 깊은 수준에서도 ','로 대체 할 수 있습니다. 예를 들면 :

`(1 2 (3 ,(+ 4 5)))
      (1 2 (3 9))

특수 마커 ', @'를 사용하여 평가 된 값을 결과 목록에 스플 라이스 할 수도 있습니다. 스 플라이 싱 된 목록의 요소는 결과 목록의 다른 요소와 동일한 수준의 요소가됩니다. '`'를 사용하지 않는 동등한 코드는 종종 읽을 수 없습니다. 여기 몇 가지 예가 있어요.

(setq some-list '(2 3))
      (2 3)

(cons 1 (append some-list '(4) some-list))
      (1 2 3 4 2 3)

`(1 ,@some-list 4 ,@some-list)
      (1 2 3 4 2 3)

1
Code is data and data is code.  There is no clear distinction between them.

이것은 lisp 프로그래머가 알고있는 고전적인 문장입니다.

코드를 인용하면 그 코드는 데이터가됩니다.

1 ]=> '(+ 2 3 4)
;Value: (+ 2 3 4)

1 ]=> (+ 2 3 4)
;Value: 9

코드를 인용하면 결과는 해당 코드를 나타내는 데이터가됩니다. 따라서 프로그램을 나타내는 데이터로 작업하려면 해당 프로그램을 인용합니다. 이것은 목록뿐만 아니라 원자 식에도 유효합니다.

1 ]=> 'code
;Value: code

1 ]=> '10
;Value: 10

1 ]=> '"ok"
;Value: "ok"

1 ]=> code
;Unbound variable: code

lisp에 포함 된 프로그래밍 언어를 만들고 싶다고 가정하면 '(+ 2 3)프로그램에 의미 론적 해석을 제공 하여 스키마 (예 :)에 인용되고 생성 한 언어의 코드로 해석되는 프로그램으로 작업하게됩니다. 이 경우 데이터를 유지하기 위해 따옴표를 사용해야합니다. 그렇지 않으면 외부 언어로 평가됩니다.

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