ProgramingTip

Lisp는 어떻게 언어 자체를 재정의 할 수 있습니까?

bestdevel 2020. 12. 4. 19:50
반응형

Lisp는 어떻게 언어 자체를 재정의 할 수 있습니까?


Lisp를 통해 언어를 자체적으로 재정의 할 수 없습니까? 누구나 어디에 있습니까?


Lisp 사용자는 Lisp를 프로그래밍 가능한 프로그래밍 언어라고 합니다. 기호는 - 기호로 계산 하는 데 사용 됩니다.

매크로는 상징적 패러다임을 이용하는 유일한 방법입니다. 더 넓은 비전은 Lisp가 수학 용어, 논리 표현, 반복 문, 규칙, 제약 설명 등 기호 표현을 설명하는 쉬운 방법을 제공하는 것입니다. 매크로 (Lisp 소스 형식의 변환)는 기호의 한 응용 프로그램 일뿐입니다.

여기에는 특정이 있습니다. 언어 '재정의'에 대해 엄격하게 재정의는 기존 언어 (구문, 의미론, 실용 학)를 재정의하는 것을 의미합니다. 그러나 언어 기능의 확장, 임베딩, 제거도 있습니다.

Lisp 전통에서는 기능을 제공하려는 많은 시도가 있습니다. Lisp 방언과 특정 구현은 그중 일부만 제공 할 수 있습니다.

주요 Common Lisp 구현에서 제공하는 기능을 재정의 / 변경 / 확장하는 몇 가지 방법 :

  • s- 저장 구문 . s- 문법의 구문은 고정되어 있지 않습니다. 리더 (READ 기능)는 소위 읽기 테이블을 사용합니다. 문자를 읽을 때 사용할 때 함수를 지정합니다. 읽기 테이블을 수정하고 만들 수 있습니다. 예를 들어 목록, 기호 또는 기타 데이터 개체의 구문을 사용할 수 있습니다. 새로운 또는 기존 데이터 유형 (예 : 해시 테이블)에 대한 새로운 구문을 도입 할 수도 있습니다. s-expression 구문을 완전히 바꾸고 다른 구문 분석을 사용할 수 있습니다. 새 파서가 Lisp 양식을 반환하는 경우 인터프리터 또는 컴파일러에 대한 변경이 필요하지 않습니다. 전형적인 예는 중위 식을 읽을 수있는 읽기 매크로입니다. 대신 읽기 매크로 내에서 연산자에 대한 중위 식 및 우선 순위 규칙이 사용됩니다. 읽기 매크로는 일반 매크로와 문서입니다. 읽기 매크로는 Lisp 데이터 구문의 문자 수준에서 작동합니다.

  • 대체 기능 . 최상위 수준 함수는 기호에 바인딩됩니다. 사용자는이 바인딩을 설명 수 있습니다. 대부분의 구현에는 많은 내장 함수가 있습니다. 내장 함수 ROOM에 대한 대안을 제공하려는 경우 해당 정의를 변경할 수 있습니다. 일부 구현에서는 오류가 다음 변경을 계속할 수있는 옵션을 제공합니다. 전체 패키지 잠금을 해제해야합니다. 이것은 일반적으로 기능이 새로운 정의로 대체 될 수 있음을 의미합니다. 여기에는 한계가 있습니다. 하나는 컴파일러가 코드에서 함수를 인라인 할 수있는 것입니다. 효과를 보려면 변경된 코드를 사용하는 코드를 다시 구입해야합니다.

  • 조언 기능 . 함수에 몇 가지 동작을 추가하려고합니다. 이것은 Lisp 세계에서 '자문'이라고합니다. 많은 Common Lisp 구현이 기능을 제공합니다.

  • 맞춤 패키지 . 패키지는 이름 공간에서 기호를 그룹화합니다. COMMON-LISP 패키지는 ANSI Common Lisp 표준의 일부인 모든 기호의 홈입니다. 프로그래머는 기존 기호를 새 패키지를 만들 수 있습니다. 따라서 프로그램에서 더 많거나 다른 기능을 제공하는 EXTENDED-COMMON-LISP 패키지를 사용할 수 있습니다. (인-패키지 "EXTENDED-COMMON-LISP")를 추가하기 만하면 자신의 확장 된 Common Lisp 버전을 사용하여 개발을 시작할 수 있습니다. 사용하는 네임 스페이스에 따라 사용하는 Lisp 방언이 약간 또는 근본적으로 다를 수 있습니다. Lisp Machine의 Genera에는 ZetaLisp, CLtL1, ANSI Common Lisp 및 Symbolics Common Lisp와 같은 여러 Lisp 방언이 나란히 있습니다.

  • CLOS 및 동적 개체. Common Lisp Object System에는 변경 사항이 내장되어 있습니다. Meta-Object Protocol은 기능을 확장합니다. CLOS 자체는 CLOS에서 확장 / 재정의 할 수 있습니다. 다른 상속을 원합니다. 방법을 작성하십시오. 인스턴스를 저장하는 다른 방법을 원합니다. 방법을 작성하십시오. 더 많은 정보가 있어야합니다. 지금 대한 수업을 제공하십시오. CLOS 자체는 다양한 객체 지향 프로그래밍 언어의 전체 '지역'을 구현할 수 있도록 설계되었습니다. 공통 예는 유형, 외부 객체 시스템 (Objective C와 같은)과의 통합, 지속성 추가하는 것입니다.

  • Lisp 양식 . Lisp 형식의 해석은 매크로를 사용하여 재정의 할 수 있습니다. 매크로는 포함 된 소스 코드를 구문 분석하고 설명 수 있습니다. 변환 프로세스를 제어하는 ​​방법에는 여러 가지가 있습니다. 복잡한 매크로는 Lisp 양식의 구문을 이해하고 변환을 적용 할 수있는 코드 워커를 사용합니다. 매크로는 사소 할 수 있습니다. LOOP 또는 ITERATE 매크로처럼 매우 복잡 할 수 있습니다. 다른 일반적인 예는 SQL 및 역할 HTML 생성을위한 매크로입니다. 매크로를 사용하여 계산을 시간으로 사용할 수도 있습니다. 컴파일러 자체가 Lisp 프로그램을 통해 임의의 계산을 수행 할 수 있습니다. 예를 들어, 여기서 특정 변수가 사용되는 경우 Lisp 매크로는 최적화 된 버전의 공식을 사용할 수 있습니다.

  • 기호 . Common Lisp는 매크로를 제공합니다. 여러 매크로를 사용하면 소스 코드에서 기호의 의미를 사용할 수 있습니다. 일반적인 예는 다음과 가변적입니다. (with-slots (foo) bar (+ foo 17)) 여기서 WITH-SLOTS로 묶인 소스의 기호 FOO는 호출 (슬롯 값 막대 'foo)로 대체됩니다.

  • 최적화 , 소위 컴파일러 매크로를 사용하면 일부 기능의보다 편리한 버전을 제공 할 수 있습니다. 컴파일러는 매크로를 사용합니다. 이 사용자가 최적화를 프로그래밍하는 방법입니다.

  • 조건 처리 -특정 방식으로 프로그래밍 언어를 사용하여 발생하는 조건을 처리합니다. Common Lisp는 오류를 처리하는 고급 방법을 제공합니다. 조건 시스템을 사용하여 언어 기능을 재정의 할 수도 있습니다. 예를 들어 내장되어있는 자동로드 기능을 처리 할 수 ​​있습니다. Lisp에서 정의되지 않은 함수를 볼 때 디버거에 함수를 대신 오류 처리기가 함수를 자동로드하고 필요한 코드를로드 한 후 작업을 다시 시도 할 수 있습니다.

  • 특수 변수 -기존 코드에 변수 바인딩을 삽입합니다. Common Lisp와 같은 많은 Lisp 방언은 특수 / 동적 변수를 제공합니다. 결혼식 가치는 스택에서 실행됩니다. 이를 통해 기존의 코드를 변경하지 않고 기존 코드에 영향을주는 변수 바인딩을 추가 할 수 있습니다. 일반적인 예는 * standard-output *과 같은 변수입니다. 변수를 리 바인드 할 수 있고 새 바인딩의 동적 범위 동안이 변수를 사용하는 모든 출력은 새로운 방향으로 이동합니다. Richard Stallman은 Emacs Lisp에서 기본으로 설정되어 점에서 매우 중요하다고 주장했습니다 (Stallman은 Scheme 및 Common Lisp에서 어휘 바인딩에 대해 알고 있었음에도 불구하고).

Lisp는 다양한 언어와 프로그래밍 패러다임을 구현하는 데 사용되었으므로 다양한 언어와 프로그래밍이 가능합니다. 전형적인 예는 Prolog와 같은 논리 언어의 역할 구현입니다. Lisp를 사용하면 s- 사용하여 Prolog 용어를 설명 할 수 있습니다. Prolog 용어는 Lisp 코드로 사용할 수 있습니다. 일반적인 일반적인 Prolog 구문이 필요한 경우 파서가 일반적인 Prolog 용어를 Lisp 형식으로 구문 분석 한 다음 적용됩니다. 언어의 다른 예로는 규칙 기반 언어, 수학 사용, SQL 용어, 인라인 Lisp 어셈블러, HTML, XML 등이 있습니다.


새로운 구문을 정의 할 때 Scheme이 Common Lisp와 추가. 사용 define-syntax되는 소스 코드에 적용되는 템플릿을 정의 할 수 있습니다 . 함수처럼 보이지만 시간에 실행되고 AST를 변환합니다.

다음 let은 .NET 용어로 정의 할 수있는 방법의 예 입니다 lambda. 포함 된 줄 let은 일치하는 패턴이고 포함 된 줄 lambda은 결과 코드 템플릿입니다.

(define-syntax let
  (syntax-rules ()
    [(let ([var expr] ...) body1 body2 ...)
     ((lambda (var ...) body1 body2 ...) expr ...)]))

이것은 대체와 같은 것이 아닙니다. 정의 된 환경에서 의 정의를 사용하기 때문에 실제로 재정의 할 수 있으며 lambda위의 정의 let는 여전히 작동 합니다. 기본적으로 매크로처럼 강력하지만 함수처럼 깔끔합니다.lambdalet


매크로는 이것을 말하는 일반적인 이유입니다. 아이디어는 코드가 데이터 구조 (트리, 다소간) 일 뿐이므로이 데이터 구조를 생성하는 프로그램을 작성할 수 있다는 것입니다. 따라서 데이터 구조를 생성하고 조작하는 프로그램을 작성하는 방법에 대해 알고있는 모든 것은 표현 적으로 코딩 할 수있는 능력을 추가합니다.

매크로는 제한이 있기 때문에 적어도 내가 아는 한 언어의 완전한 재정의는 아닙니다. 매크로는 코드의 단일 하위 트리 만 가져와이를 대체 할 단일 하위 트리를 생성 할 수 있습니다. 따라서 전체 프로그램 변환 매크로를 작성할 수는 없습니다.

그러나 매크로는 여전히 많은 작업을 수행 할 수 있습니다. 확실히 다른 어떤 언어보다 더 많은 작업을 수행 할 수 있습니다. 그리고 정적 컴파일을 사용하는 경우 전체 프로그램 변환을 수행하는 것이 전혀 어렵지 않으므로 제한은 큰 문제가 아닙니다.


'컴퓨터 프로그램의 구조 및 해석'4-5 장에 대한 참조는 답변에서 누락 된 부분입니다 ( 링크 ).

이 장은 Lisp에서 Lisp 평가자를 구축하는 방법을 안내합니다. 나는 새로운 평가자에서 Lisp를 재정의하는 방법을 보여줄뿐만 아니라 Lisp 프로그래밍 언어의 사양에 대해 배울 수 있기 때문에 읽기를 좋아합니다.


이 답변은 특히 Common Lisp (이하 CL)에 관한 것이지만 답변의 일부는 lisp 제품군의 다른 언어에 적용될 수 있습니다.

CL은 S- 표현식을 사용하고 (대부분) 함수 응용 프로그램의 시퀀스처럼 보이기 때문에 내장 코드와 사용자 코드 사이에 명백한 차이가 없습니다. 주요 차이점은 "언어가 제공하는 것"이 ​​코딩 환경 내의 특정 패키지에서 사용할 수 있다는 것입니다.

약간의주의를 기울이면 대체 코드를 작성하고 대신 사용하는 것이 어렵지 않습니다.

이제 "일반"판독기 (소스 코드를 읽고 내부 표기법으로 바꾸는 부분)는 소스 코드가 다소 특정한 형식 (괄호로 묶인 S- 표현식) 일 것으로 예상하지만 판독기는 "읽기- 테이블 "은 개발자가 만들고 수정할 수 있으며 소스 코드의 모양을 변경할 수도 있습니다.

이 두 가지는 적어도 Common Lisp가 재 프로그래밍 가능한 프로그래밍 언어로 간주 될 수있는 이유에 대한 근거를 제공해야합니다. 간단한 예는 없지만 Common Lisp를 스웨덴어로 번역 한 부분을 일부 구현했습니다 (몇 년 전인 4 월 1 일에 생성됨).


밖에서 보면 ...

나는 항상 Lisp가 기본 구성 요소에서 모든 논리 프로세스를 빌드 할 수있는 (그리고 도구 세트와 추가 기능으로 빌드 및 제공되는) 기본 원자 논리 연산자를 핵심적으로 제공했기 때문이라고 생각했습니다.

기본 정의가 너무 가단해서 어떤 형태도 취할 수 있고 어떤 형태도 구조로 가정 / 추정되지 않기 때문에 스스로 재정의 할 수있는 것은 아닙니다.

은유 적으로 유기 화합물 만 있으면 유기 화학을하고, 금속 산화물 만 있으면 야금술을하지만 원소 만 있으면 모든 것을 할 수 있지만 완료해야 할 추가 초기 단계가 있습니다. 당신을 위해 이미 ....

제 생각에는 .....


http://www.cs.colorado.edu/~ralex/papers/PDF/X-expressions.pdf의 멋진 예

판독기 매크로는 S- 표현식과 공존 할 X- 표현식을 정의합니다. 예 :

? (cx <circle cx="62" cy="135" r="20"/>) 
62

평범한 바닐라 Common Lisp http://www.AgentSheets.com/lisp/XMLisp/XMLisp.lisp ...

(eval-when (:compile-toplevel :load-toplevel :execute)
  (when (and (not (boundp '*Non-XMLISP-Readtable*)) (get-macro-character #\<))
    (warn "~%XMLisp: The current *readtable* already contains a #/< reader function: ~A" (get-macro-character #\<))))

... 물론 XML 파서는 그렇게 간단하지는 않지만 lisp 리더에 연결하는 것입니다.

참고 URL : https://stackoverflow.com/questions/2307562/how-does-lisp-let-you-redefine-the-language-itself

반응형