IT

Lisp에 관한 Paul Graham의 요점을 설명하십시오

lottoking 2020. 6. 18. 07:31
반응형

Lisp에 관한 Paul Graham의 요점을 설명하십시오


폴 그레이엄 (Paul Graham)의 리스프를 다르게 만든 것의 요점을 이해하는 데 도움이 필요합니다 .

  1. 새로운 변수 개념. Lisp에서 모든 변수는 사실상 포인터입니다. 값은 변수가 아닌 유형을 갖는 것이므로 변수를 할당하거나 바인딩하는 것은 포인터가 가리키는 것이 아니라 포인터를 복사하는 것을 의미합니다.

  2. 심볼 타입. 포인터를 비교하여 동등성을 테스트 할 수 있다는 점에서 기호는 문자열과 다릅니다.

  3. 기호 트리를 사용하는 코드 표기법.

  4. 항상 사용 가능한 언어입니다. 읽기 시간, 컴파일 시간 및 런타임은 실제로 구별되지 않습니다. 코드를 읽거나 컴파일하는 동안 코드를 컴파일 또는 실행하고, 컴파일하는 동안 코드를 읽거나 실행하며, 런타임에 코드를 읽거나 컴파일 할 수 있습니다.

이 요점은 무엇을 의미합니까? C 또는 Java와 같은 언어에서 어떻게 다른가요? Lisp 패밀리 언어 이외의 다른 언어에 이러한 구성이 있습니까?


Matt의 설명은 완벽합니다. 그는 C와 Java와 비교해 보았습니다.하지만하지 않을 것입니다. 그러나 어떤 이유로 나는이 주제에 대해 한 번 이야기하는 것을 정말로 좋아합니다. 대답에.

포인트 (3)과 (4)에서 :

목록의 포인트 (3)과 (4)가 가장 흥미롭고 여전히 관련성이 있습니다.

그것들을 이해하려면 프로그래머가 입력 한 문자 스트림 형태의 Lisp 코드로 실행되는 과정을 명확하게 파악하는 것이 유용합니다. 구체적인 예를 보자.

;; a library import for completeness,
;; we won't concern ourselves with it
(require '[clojure.contrib.string :as str])

;; this is the interesting bit:
(println (str/replace-re #"\d+" "FOO" "a123b4c56"))

Clojure 코드 스 니펫이 출력됩니다 aFOObFOOcFOO. 읽기 시간이 실제로 사용자 코드에 개방적이지 않기 때문에 Clojure는 목록의 네 번째 요점을 완전히 만족 시키지는 않습니다. 그러나 이것이 그렇지 않다는 것이 무엇을 의미하는지 논의 할 것입니다.

따라서이 코드를 파일에 저장하고 Clojure에 실행을 요청한다고 가정하십시오. 또한 (간단 성을 위해) 라이브러리 가져 오기를 지난 것으로 가정했습니다. 흥미로운 비트 는 오른쪽 (println에서 시작 )하여 오른쪽 끝에서 끝납니다 . 이것은 예상대로 어휘 분석되고 이미 중요한 요점이 발생합니다. 결과는 특별한 컴파일러 특정 AST 표현이 아닙니다. 일반적인 Clojure / Lisp 데이터 구조입니다 . 즉, 많은 기호가 포함 된 중첩 된 목록입니다. 문자열,이 경우에는 컴파일 된 단일 정규식 패턴 객체#"\d+"리터럴 (자세한 내용은 아래 참조). 일부 Lisp은이 프로세스에 약간의 왜곡을 가하지 만 Paul Graham은 대부분 Common Lisp를 언급했습니다. 귀하의 질문과 관련하여 Clojure는 CL과 유사합니다.

컴파일 타임에 전체 언어 :

이 시점 이후 모든 컴파일러는 Lisp 인터프리터의 경우에도 마찬가지입니다. Clojure 코드는 항상 컴파일됩니다) Lisp 데이터 구조는 Lisp 프로그래머가 조작하는 데 사용됩니다. 이 시점에서 Lisp 프로그래머가 Lisp 프로그램을 나타내는 Lisp 데이터를 조작하고 변환 된 프로그램을 나타내는 변환 된 데이터를 출력하는 원본을 대신하여 사용하는 Lisp 함수를 작성할 수있는 놀라운 가능성이 명백해집니다. 다시 말해, Lisp 프로그래머가 함수를 Lisp에서 매크로라고하는 일종의 컴파일러 플러그인으로 등록 할 수없는 이유는 무엇입니까? 실제로 어떤 Lisp 시스템에도이 용량이 있습니다.

따라서 매크로는 실제 객체 코드가 생성 될 때 최종 컴파일 단계 전에 컴파일 타임에 프로그램 표현에서 작동하는 일반적인 Lisp 함수입니다. 실행할 수있는 코드 매크로의 종류에는 제한이 없으므로 (특히, 매크로 코드를 자유롭게 사용하여 코드 자체를 작성하는 경우가 많음) "컴파일 타임에 전체 언어를 사용할 수 있습니다" ".

읽을 때 전체 언어 :

#"\d+"정규식 리터럴 로 돌아가 봅시다 . 위에서 언급했듯이, 컴파일러가 컴파일을 위해 준비중인 새 코드에 대한 첫 번째 언급을 듣기 전에 읽기 시간에 실제 컴파일 된 패턴 객체로 변환됩니다. 어떻게 이런 일이 발생합니까?

Clojure가 현재 구현되는 방식은 Paul Graham이 생각한 것과 약간 다르지만 영리한 해킹으로 가능합니다 . Common Lisp에서 이야기는 개념적으로 약간 깨끗합니다. 그러나 기본 사항은 비슷합니다. Lisp Reader는 상태 전이를 수행하고 결국 "수락 상태"에 도달했는지 여부를 선언하는 상태 머신은 문자가 나타내는 Lisp 데이터 구조를 뱉어냅니다. 따라서 문자 123는 숫자 123등이됩니다. 이제 중요한 점이 있습니다. 이 상태 머신은 사용자 코드로 수정할 수 있습니다. (앞에서 언급했듯이, CL의 경우에는 전적으로 사실입니다. Clojure의 경우 해킹 (감소 및 실제로 사용되지 않음)이 필요합니다. 그러나 나는 PG의 기사이므로 자세히 설명해야합니다 ...)

따라서 공통 Lisp 프로그래머이고 Clojure 스타일의 벡터 리터럴에 대한 아이디어가 마음에 들면 독자에게 일부 문자 시퀀스에 적절하게 반응하는 함수를 연결 [하거나 #[처리 할 수 ​​있습니다. 일치에서 끝나는 문자 벡터의 시작 ]. 이러한 기능을 리더 매크로 라고하며 일반 매크로 와 마찬가지로 이전에 등록 된 리더 매크로에서 활성화 된 펑키 표기법으로 작성된 코드를 포함하여 모든 종류의 Lisp 코드를 실행할 수 있습니다. 그래서 당신을 위해 읽기에 전체 언어가 있습니다.

그것을 마무리 :

실제로, 지금까지 증명 된 것은 읽기 또는 컴파일 시간에 일반 Lisp 함수를 실행할 수 있다는 것입니다. 읽기, 컴파일 또는 런타임에서 읽기와 컴파일이 어떻게 가능한지 이해하기 위해 여기에서 취해야 할 한 단계는 읽기와 컴파일이 Lisp 함수에 의해 수행된다는 것을 인식하는 것입니다. 문자 스트림에서 Lisp 데이터를 읽거나 Lisp 코드를 각각 컴파일하고 실행하기 위해 언제든지 호출 read하거나 호출 할 수 있습니다 eval. 그것은 항상 모든 언어입니다.

Lisp가 목록에서 포인트 (3)을 충족한다는 점이 포인트 (4)를 충족시키는 방식에 필수적이라는 점에 주목하십시오. Lisp가 제공하는 특정 매크로는 일반적인 Lisp 데이터로 표현되는 코드에 크게 의존합니다. 그것은 (3)에 의해 가능하게 된 것입니다. 우연히도 코드의 "트리-쉬쉬 (tree-ish)"측면 만 중요합니다. XML을 사용하여 Lisp를 작성할 수있을 것입니다.


1) 새로운 변수 개념. Lisp에서 모든 변수는 사실상 포인터입니다. 값은 변수가 아닌 유형을 갖는 것이므로 변수를 할당하거나 바인딩하는 것은 포인터가 가리키는 것이 아니라 포인터를 복사하는 것을 의미합니다.

(defun print-twice (it)
  (print it)
  (print it))

'it' is a variable. It can be bound to ANY value. There is no restriction and no type associated with the variable. If you call the function, the argument does not need to be copied. The variable is similar to a pointer. It has a way to access the value that is bound to the variable. There is no need to reserve memory. We can pass any data object when we call the function: any size and any type.

The data objects have a 'type' and all data objects can be queried for its 'type'.

(type-of "abc")  -> STRING

2) A symbol type. Symbols differ from strings in that you can test equality by comparing a pointer.

A symbol is a data object with a name. Usually the name can be used to find the object:

|This is a Symbol|
this-is-also-a-symbol

(find-symbol "SIN")   ->  SIN

Since symbols are real data objects, we can test whether they are the same object:

(eq 'sin 'cos) -> NIL
(eq 'sin 'sin) -> T

This allows us for example to write a sentence with symbols:

(defvar *sentence* '(mary called tom to tell him the price of the book))

Now we can count the number of THE in the sentence:

(count 'the *sentence*) ->  2

In Common Lisp symbols not only have a name, but they also can have a value, a function, a property list and a package. So symbols can be used to name variables or functions. The property list is usually used to add meta-data to symbols.

3) A notation for code using trees of symbols.

Lisp uses its basic data structures to represent code.

The list (* 3 2) can be both data and code:

(eval '(* 3 (+ 2 5))) -> 21

(length '(* 3 (+ 2 5))) -> 3

The tree:

CL-USER 8 > (sdraw '(* 3 (+ 2 5)))

[*|*]--->[*|*]--->[*|*]--->NIL
 |        |        |
 v        v        v
 *        3       [*|*]--->[*|*]--->[*|*]--->NIL
                   |        |        |
                   v        v        v
                   +        2        5

4) The whole language always available. There is no real distinction between read-time, compile-time, and runtime. You can compile or run code while reading, read or run code while compiling, and read or compile code at runtime.

Lisp provides the functions READ to read data and code from text, LOAD to load code, EVAL to evaluate code, COMPILE to compile code and PRINT to write data and code to text.

These functions are always available. They don't go away. They can be part of any program. That means any program can read, load, eval or print code - always.

How are they different in languages like C or Java?

Those languages don't provide symbols, code as data or runtime evaluation of data as code. Data objects in C are usually untyped.

Do any other languages other than LISP family languages have any of these constructs now?

Many languages have some of these capabilities.

The difference:

In Lisp these capabilities are designed into the language so that they are easy to use.


For points (1) and (2), he is talking historically. Java's variables are pretty much the same, which is why you need to call .equals() to compare values.

(3) is talking about S-expressions. Lisp programs are written in this syntax, which provides lots of advantages over ad-hoc syntax like Java and C, such as capturing repeated patterns in macros in a far cleaner way than C macros or C++ templates, and manipulating code with the same core list operations that you use for data.

(4) taking C for example: the language is really two different sub languages: stuff like if() and while(), and the preprocessor. You use the preprocessor to save having to repeat yourself all the time, or to skip code with #if/#ifdef. But both languages are quite separate, and you can't use while() at compile time like you can #if.

C++ makes this even worse with templates. Check out a few references on template metaprogramming, which provides a way of generating code at compile time, and is extremely difficult for non-experts to wrap their heads around. In addition, it's really a bunch of hacks and tricks using templates and macros that the compiler can't provide first class support for - if you make a simple syntax error, the compiler is unable to give you a clear error message.

Well, with Lisp, you have all this in one single language. You use the same stuff to generate code at run time as you learn in your first day. This isn't to suggest metaprogramming is trivial, but it is certainly more straightforward with first class language and compiler support.


Points (1) and (2) would also fit Python. Taking a simple example "a = str(82.4)" the interpreter first creates a floating point object with value 82.4. Then it calls a string constructor which then returns a string with value '82.4'. The 'a' on the left hand side is merely a label for that string object. The original floating point object was garbage collected because there are no more references to it.

In Scheme everything is treated as an object in a similar manner. I'm not sure about Common Lisp. I would try to avoid thinking in terms of C/C++ concepts. They slowed me down heaps when I was trying to get my head around the beautiful simplicity of Lisps.

참고URL : https://stackoverflow.com/questions/2710231/please-explain-some-of-paul-grahams-points-on-lisp

반응형