[lisp] Lisp에서 ‘(또는 따옴표)를 언제 사용합니까?

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

그것은 무엇을합니까?



답변

단답형
기본 평가 규칙을 무시하고 표현식 (기호 또는 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 는 이에 대한 좋은 설명을 제공합니다.

해피 해킹!


답변

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

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


답변

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

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

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

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


답변

이 질문에 대한 한 가지 대답은 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가 반환하는 데이터는 모든 의도와 목적을 위해 실행중인 코드의 일부로 간주되므로 읽기 전용으로 처리해야합니다!


답변

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

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

(quote a)
'a

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

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

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


답변

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의 사람들에게 감사드립니다.


답변

인수 값을 전달하는 대신 인수 자체를 전달하려면 따옴표를 사용합니다. 이것은 대부분 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 값을 확인하고 값을 전달합니다. 그것. 그 이후로 우리는 가치를 제공하지 않았습니다.