Lisp와 유사한 구문 확장 메커니즘을 사용하여 프로그래밍 언어 [닫기]


20

나는 Lisp에 대한 제한된 지식 (자유 시간에 조금 배우려고 노력)을 가지고 있지만 Lisp 매크로를 이해하는 한 Lisp 자체에서 새로운 언어 구조와 구문을 설명 할 수 있습니다. 이는 Lisp 컴파일러 / 인터프리터를 변경하지 않고 새로운 구문을 라이브러리로 추가 할 수 있음을 의미합니다.

이 방법은 다른 프로그래밍 언어와는 매우 다릅니다. 예를 들어, 새로운 종류의 루프 또는 특정 관용구로 Pascal을 확장하려면 언어의 구문과 의미를 확장 한 다음 컴파일러에서 새로운 기능을 구현해야합니다.

언어 자체 내에서 언어를 확장 할 수있는 유사한 가능성을 제공하는 Lisp 제품군 외부에 다른 프로그래밍 언어가 있습니까 (예 : Common Lisp, Scheme, Clojure (?), Racket (?) 등)?

편집하다

긴 토론을 피하고 답변에 구체적으로 적어주십시오. 어떤 방식 으로든 확장 될 수있는 프로그래밍 언어의 긴 목록 대신, 개념적인 관점에서 확장 메커니즘으로서 Lisp 매크로에 특정한 것이 무엇인지, 그리고 어떤 비 Lisp 프로그래밍 언어가 어떤 개념을 제공하는지 이해하고 싶습니다 그것은 그들에게 가깝습니다.


6
Lisp에는 일반 매크로 외에 다른 트릭이 있습니다. "판독기 매크로"를 사용하면 구문 분석기 구문을 런타임에 캡처하고 확장 할 수 있으므로 언어의 기본 토큰 구조도 제어 할 수 있습니다.
ddyer

@ ddyer : 고마워요, 그것에 대해 몰랐습니다 : 내 독서 목록에 추가 될 또 다른 주제.
조르지오

루비 메타 프로그래밍이 이것을 충족시킬 수 있습니다.
Rig

1
귀하의 질문은 모순입니다. 먼저 목록을 요청한 다음 개념적 정보를 요청하십시오.

나는 목록을 요구하지만 너무 일반적인 것이기 때문에 일반적인 언어 (어떤 방식으로 확장 될 수있는 프로그래밍 언어가 아님)는 요구하지 않습니다. Lisp와 비슷한 방식으로 확장 할 수있는 언어에 대해 알고 싶습니다 (확장자는 메타 언어가 아닌 확장과 동일한 언어를 사용하여 정의됩니다). Péter Török, Thomas Eding, SK-logic 및 Mechanical 달팽이의 대답은 내가 생각했던 것과 가장 가까운 것 같습니다. 그래도 여전히 모든 대답을주의 깊게 읽어야합니다.
조르지오

답변:


19

스칼라는 이것을 가능하게한다 (사실은 새로운 언어 구조와 완전한 DSL의 정의를 지원하도록 의도적으로 설계되었다).

기능적 언어에서 일반적으로 사용되는 고차 함수, 람다 및 카레 외에도 다음과 같은 특수 언어 기능이 있습니다.

  • 연산자 없음-모든 것이 함수이지만 함수 이름에는 '+', '-'또는 ':'와 같은 특수 문자가 포함될 수 있습니다.
  • 점과 중괄호는 단일 매개 변수 메소드 호출에 대해 생략 할 수 있습니다. 즉, 중위 형식 a.and(b)과 같습니다.a and b
  • 단일 매개 변수 함수 호출의 경우 일반 중괄호 대신 중괄호를 사용할 수 있습니다-이것은 (카레와 함께) 다음과 같은 것을 쓸 수 있습니다

    val file = new File("example.txt")
    
    withPrintWriter(file) {
      writer => writer.println("this line is a function call parameter")
    }
    

    여기서 withPrintWriter, 두 번의 두 파라미터를 파라미터리스트 평범한 방법이 포함된다

  • 이름 별 매개 변수를 사용하면 람다로 빈 매개 변수 목록을 생략하여 다음과 같이 myAssert(() => x > 3)짧은 형식으로 호출을 작성할 수 있습니다.myAssert(x > 3)

예제 DSL 작성에 대해서는 11 장 무료 책 Programming Scala의 스칼라 에서 도메인 특정 언어에 자세히 설명되어 있습니다.

* 나는 이것이 스칼라에 독특하다는 것을 의미하지는 않지만 최소한 공통적 인 것은 아닙니다. 그래도 기능 언어 전문가는 아닙니다.


1
+1 : 흥미 롭습니다. 이것은 구문을 확장하기 위해 새로운 클래스를 정의 할 수 있고 메소드 서명이 새로운 구문을 부산물로 제공한다는 것을 의미합니까?
조르지오

@Giorgio, 기본적으로 예.
Péter Török

링크가 더 이상 작동하지 않습니다.
Nate Glenn

13

Perl은 언어의 사전 처리를 허용합니다. 이것은 언어의 구문을 근본적으로 바꾸는 정도로 자주 사용되지는 않지만, 이상한 모듈 중 일부에서 볼 수 있습니다.

펄이 파이썬으로 작성된 것처럼 보이는 코드를 실행할 수있게하는 모듈도 있습니다.

perl 내에서 이에 대한보다 현대적인 접근 방식은 Filter :: Simple (perl5의 핵심 모듈 중 하나)을 사용하는 것입니다.

이러한 모든 사례에는 "Mad Doctor of Perl"이라고하는 Damian Conway가 포함되어 있습니다. 펄 내에서 여전히 언어를 원하는 방식으로 바꿀 수있는 놀랍도록 강력한 기능입니다.

이것과 다른 대안에 대한 더 많은 문서는 perlfilter에 있습니다.


13

하스켈

Haskell에는 "Quasiquotation"뿐만 아니라 "Template Haskell"도 있습니다.

http://www.haskell.org/haskellwiki/Template_Haskell

http://www.haskell.org/haskellwiki/Quasiquotation

이러한 기능을 통해 사용자는 일반적인 방법 이외의 언어 구문을 극적으로 추가 할 수 있습니다. 이것들은 컴파일시에도 해결되며, 나는 적어도 컴파일 된 언어의 경우 큰 필요하다고 생각합니다 [1].

C와 같은 언어로 고급 패턴 매처를 만들기 위해 Haskell에서 한 번 인용 부호를 사용했습니다.

moveSegment :: [Token] -> Maybe (SegPath, SegPath, [Token])
moveSegment [hc| HC_Move_Segment(@s, @s); | s1 s2 ts |] = Just (mkPath s1, mkPath s2, ts)
moveSegment _ = Nothing

[1] 그 외에는 다음과 같은 구문 확장이 가능합니다. runFeature "some complicated grammar enclosed in a string to be evaluated at runtime"물론 이것은 많은 쓰레기입니다.


3
Haskell의 다른 기능들도 본질적으로 자신 만의 연산자를 생성하거나 람다 함수와 결합 된 자동 커링 (예 :의 일반적인 사용법 forM) 과 같은 사용자 정의 구문을 허용합니다 .
Xion

솔직히 카레와 맞춤 연산자는 자격이 없다고 생각합니다. 언어를 깔끔하게 사용할 수는 있지만 / new / 기능을 언어에 추가 할 수는 없습니다. TH와 QQ는 그렇습니다. 엄격한 의미에서 TH와 QQ는 그들이 의도 한 바대로 수행한다는 의미에서 TH와 QQ를 수행하지는 않지만 컴파일 타임에 실제로 "언어에서 벗어날"수 있습니다.
Thomas Eding

1
"다음은 구문 확장으로서 자격이 있습니다 ...": 아주 좋은 지적입니다.
Giorgio

12

Tcl 은 확장 가능한 구문을 지원하는 오랜 역사를 가지고 있습니다. 예를 들어, 다음은 카디널, 사각형 및 큐브에 대해 세 개의 변수 (중지 될 때까지)를 반복하는 루프 구현입니다.

proc loopCard23 {cardinalVar squareVar cubeVar body} {
    upvar 1 $cardinalVar cardinal $squareVar square $cubeVar cube

    # We borrow a 'for' loop for the implementation...
    for {set cardinal 0} true {incr cardinal} {
        set square [expr {$cardinal ** 2}]
        set cube [expr {$cardinal ** 3}]

        uplevel 1 $body
    }
}

그러면 다음과 같이 사용됩니다.

loopCard23 a b c {
    puts "got triplet: $a, $b, $c"
    if {$c > 400} {
        break
    }
}

기술의 이러한 종류의 Tcl 프로그래밍에 광범위하게 사용되며, 그 일의 열쇠가 올바로 수행 있습니다 upvaruplevel명령 ( upvar바인딩 지역 변수에 다른 범위에서 명명 된 변수와 uplevel다른 영역에서 스크립트를 실행 : 두 경우 모두에서이 1있음을 나타냅니다 해당 범위는 발신자의 범위입니다). 또한 데이터베이스 (결과 세트의 각 행에 대해 일부 코드를 실행), GUI 용 Tk (콜백을 이벤트에 바인딩하기 위해) 등에 연결하는 코드에서 많이 사용됩니다.

그러나 이는 수행되는 작업의 일부일뿐입니다. 내장 언어는 Tcl 일 필요도 없습니다. 그것은 사실상 무엇이든 될 수 있습니다 (중괄호의 균형을 잡는 한-그것이 사실이 아닌 경우 구문 론적으로 끔찍한 것입니다-프로그램의 대다수)-Tcl은 필요에 따라 임베디드 외국어로 전달할 수 있습니다. 이를 수행하는 예로는 Tcl 명령을 구현하기 위해 C를 포함 하고 Fortran과 동등합니다. (어쩌면 모든 Tcl의 내장 명령은 언어 자체가 아니라 표준 라이브러리이기 때문에 이런 식으로 수행됩니다.)


10

이것은 부분적으로 의미론의 문제입니다. Lisp의 기본 아이디어는 프로그램 자체가 조작 할 수있는 데이터라는 것입니다. Scheme과 같이 Lisp 제품군에서 일반적으로 사용되는 언어는 실제로 구문 분석기 의미에서 새로운 구문 을 추가하지 못하게합니다 . 모두 공백으로 구분 된 괄호로 묶은 목록입니다. 핵심 구문이 거의 없기 때문에 거의 모든 의미 구조를 만들 수 있습니다 . 스칼라 (아래에서 논의 됨)는 비슷합니다. 변수 이름 규칙은 너무 자유로 워서 동일한 핵심 구문 규칙을 유지하면서 멋진 DSL을 쉽게 만들 수 있습니다.

이 언어들은 실제로 Perl 필터의 의미에서 새로운 구문을 정의 할 수는 없지만 DSL을 구축하고 언어 구성을 추가하는 데 사용할 수있는 충분히 유연한 코어를 가지고 있습니다.

중요한 공통 기능은 언어에서 제공하는 기능을 사용하여 내장 언어뿐만 아니라 작동하는 언어 구문을 정의 할 수 있다는 것입니다. 이 기능에 대한 지원 정도는 다음과 같습니다.

  • 대부분의 오래된 언어는 기본으로 제공 같은 기능 sin(), round()등, 자신을 구현할 수있는 방법없이.
  • C ++은 제한된 지원을 제공합니다. 예를 들어 일부는 내장 캐스트 같은 키워드 ( static_cast<target_type>(input), dynamic_cast<>(), const_cast<>(), reinterpret_cast<>()) 템플릿 함수에 대한 부스트 사용을 사용하여 에뮬레이션 할 수있다 lexical_cast<>(), polymorphic_cast<>(), any_cast<>(), ...
  • 자바는 제어 구조 (내장하고있다 for(;;){}, while(){}, if(){}else{}, do{}while(), synchronized(){}, strictfp{})를하고 자신을 정의 할 수 없습니다. 스칼라는 편리한 컨트롤 구조와 같은 구문을 사용하여 함수를 호출 할 수있는 추상 구문을 정의하고 라이브러리는이를 사용하여 새로운 제어 구조를 효과적으로 정의합니다 (예 : react{}액터 라이브러리).

또한, Notation package 에서 Mathematica의 커스텀 문법 기능을 볼 수 있습니다 . (기술적으로는 Lisp 제품군에 있지만 일반적인 Lisp 확장 성과 일부 확장 기능이 다르게 수행됩니다.)


2
잘못된. Lisp 에서는 실제로 어떤 종류의 새로운 구문도 절대적으로 추가 할 수 있습니다. 이 예제에서와 같이 : meta-alternative.net/pfront.pdf-Lisp 매크로 일뿐 입니다.
SK-logic

이는 DSL 구축을 위해 특별히 설계된 언어 로 구현 된 것으로 보인다 . 물론 Lisp 패밀리에서 그러한 기능을 제공하는 언어를 만들 수도 있습니다. 나는 그 기능이 널리 사용되는 Lisp (예 : Scheme)을 지원하는 핵심 Lisp 아이디어가 아님을 의미했습니다. 명확히하기 위해 편집했습니다.
기계 달팽이

이 "DSL을 구축하기위한 언어"는 아주 전형적인 최소한의 Lisp 위에 구축 된 매크로 모음입니다. 으로 다른 Lisp에 쉽게 이식 할 수 있습니다 (defmacro ...). 사실 저는 현재이 언어를 라켓으로 포팅하고 있습니다. 그러나 S-expressions 구문이 유용한 유용한 의미의 대부분에 충분하기 때문에 그것이 유용하지 않은 것에 동의합니다.
SK-logic

그리고 Scheme은 R6RS부터 공식적으로 그리고 비공식적으로 연령대에 따라 Common Lisp와 다르지 않습니다 (define-macro ...).
SK-logic

8

Rebol 은 당신이 묘사하는 것과 거의 같지만 약간 옆으로 보입니다.

특정 구문을 정의하는 대신 Rebol의 모든 것은 함수 호출입니다. 키워드는 없습니다. (예, 재정의 if하고 while진정으로 원하는 경우) 가능합니다. 예를 들면 다음과 같습니다 if.

if now/time < 12:00 [print "Morning"]

if조건과 블록이라는 두 가지 인수를 취하는 함수입니다. 조건이 참이면 블록이 평가됩니다. 대부분의 언어처럼 들리나요? 블록은 데이터 구조입니다. 코드에만 국한되지는 않습니다. 예를 들어 블록 블록이며 "코드는 데이터"의 유연성에 대한 간단한 예입니다.

SomeArray: [ [foo "One"] [bar "Two"] [baz "Three"] ]
foreach action SomeArray [action/1: 'print] ; Change the data
if now/time < 12:00 SomeArray/2 ; Use the data as code - right now, if now/time < 12:00 [print "Two"]

구문 규칙을 고수 할 수있는 한,이 언어를 확장하는 것은 대부분 새로운 기능을 정의하는 것에 지나지 않습니다. 예를 들어 일부 사용자는 Rebol 3의 기능을 Rebol 2로 백 포트했습니다.


7

루비는 상당히 유연한 문법을 ​​가지고 있는데, "언어 자체 내에서 언어를 확장하는"방법이라고 생각합니다.

예는 rake 입니다. 루비로 작성되었지만 루비이지만 make 처럼 보입니다 .

몇 가지 가능성을 확인하려면 Rubymetaprogramming 키워드를 찾을 수 있습니다 .


13
"유연한 구문"은 "확장 가능한 구문"과는 매우 다릅니다. 루비로 프로그래밍 한 지 오래되었습니다.하지만 레이크는 내장 구문을 잘 설계된 것처럼 보입니다. 다시 말해, 이것은 비 예제입니다.
토마스 에딩

2
그 정도의 문제가 아닌가? 구문의 일부 측면을 확장 할 수 있지만 다른 언어는 확장 할 수없는 "확장 가능한 구문"언어와 "유연한 구문"언어를 어떻게 구별 할 수 있습니까?
오는 폭풍

1
선이 희미하면 C가 확장 가능한 구문을 지원하는 것으로 간주되도록 선을 뒤로 밀어 봅시다.
Thomas Eding

예제와 연결하기 위해 여기에 선을 그립니다. 확장 가능한 구문을 가진 언어는 레이크처럼 만들 수 있습니다. 유연한 구문을 가진 언어를 확장하여 (언어가 좋은 언어 혼합) makefile을 컴파일하고 실행할 수 있습니다. 그래도 학위 문제에 대한 당신의 요점은 좋은 것입니다. 어쩌면 일부 언어는 Make를 컴파일 할 수 있지만 파이썬은 컴파일 할 수 없습니다. 그리고 다른 사람들은 둘 다 허용합니다.
Clayton Stanley

모든 튜링 언어는 Make 파일을 처리 할 수 ​​있어야합니다. 구문의 유연성은 그다지 어려운 문제를 넘어서는 요소가 아닙니다.
Rig

7

당신이 말하는 방식으로 구문을 확장하면 도메인 특정 언어 를 만들 수 있습니다. 그렇다면 귀하의 질문을 바꾸는 가장 유용한 방법은 다른 언어가 도메인 특정 언어를 잘 지원하는 것입니다.

루비는 매우 유연한 구문을 가지고 있으며 레이크와 같은 많은 DSL이 번성했습니다. 그루비에는 그러한 장점이 많이 포함되어 있습니다. 또한 Lisp 매크로와 더 직접적으로 유사한 AST 변환도 포함합니다.

통계 컴퓨팅 언어 인 R은 함수가 인수를 평가하지 않을 수있게합니다. 이를 사용하여 회귀 수식을 지정하기위한 DSL을 만듭니다. 예를 들면 다음과 같습니다.

y ~ a + b

"k0 + k1 * a + k2 * b 형식의 줄을 y의 값에 맞추십시오"를 의미합니다.

y ~ a * b

"k0 + k1 * a + k2 * b + k3 * a * b 형식의 줄을 y의 값에 맞추십시오"를 의미합니다.

등등.


2
Groovy의 AST 변환은 Lisp 또는 Clojure 매크로에 비해 매우 장황합니다. 예를 들어 groovy.codehaus.org/Global+AST+에 있는 20 개 이상의 Groovy 예제는 Clojure에서 한 줄로 다시 쓰여질 수 있습니다 (예 :`(this (println ~ message)). 뿐만 아니라 jar를 컴파일하거나 메타 데이터를 작성하거나 해당 Groovy 페이지의 다른 내용을 작성할 필요도 없습니다.
Vorg van Geir

7

컨버전스 (Converge) 는 또 다른 비 유사 메타 프로그래밍 언어입니다. 그리고 C ++도 어느 정도 자격이 있습니다.

아마도 MetaOCaml 은 Lisp와는 거리가 멀다. 완전히 다른 스타일의 구문 확장 성을 제공하지만 여전히 강력 하려면 CamlP4를 살펴 보십시오 .

Nemerle 은 Lisp 스타일 메타 프로그래밍을 사용하는 또 다른 확장 가능한 언어이지만 Scala와 같은 언어에 더 가깝습니다.

그리고 스칼라 자체 도 곧 그러한 언어 가 될 것 입니다.

편집 : 가장 흥미로운 예 인 JetBrains MPS를 잊었습니다 . Lispish와는 거리가 멀고 텍스트가 아닌 프로그래밍 시스템으로 편집기가 AST 수준에서 직접 작동합니다.

Edit2 : 업데이트 된 질문에 대답하기 위해-Lisp 매크로에는 독특하고 예외적 인 것이 없습니다. 이론적으로 모든 언어는 이러한 메커니즘을 제공 할 수 있습니다 (평범한 C로도 수행). AST에 액세스하고 컴파일 타임에 코드를 실행하는 기능 만 있으면됩니다. 일부 반영이 도움이 될 수 있습니다 (유형, 기존 정의 등에 대한 쿼리).


스칼라 링크는 제안 된 매크로가 "스칼라의 구문을 변경할 수 없습니다"라고 명시 적으로 말합니다. (흥미롭게, 이것은 제안과 C / C ++ 전 처리기 매크로의 차이점으로 이것을 나열합니다!)
ruakh

@ruakh, 예. Converge 및 Template Haskell과 동일한 접근 방식입니다. 매크로 응용 프로그램은 명시 적으로 표시되며 "일반"구문과 혼합 할 수 없습니다. 그러나 내부에는 원하는 구문을 사용할 수 있으므로 확장 가능한 구문입니다. 안타깝게도 "비 립형"요구 사항은 옵션을 이와 같은 언어로 제한합니다.
SK-logic

"평범한 C로도 해냈습니다": 어떻게 가능합니까?
조르지오

@Giorgio는 물론 컴파일러를 수정했습니다 (매크로와 증분 모듈 컴파일이 추가되었습니다. 실제로 C에는 매우 자연 스럽습니다).
SK-logic

AST에 액세스해야하는 이유는 무엇입니까?
Elliot Gorokhovsky

6

프롤로그를 사용하면 동일한 이름의 복합 용어로 변환되는 새 연산자를 정의 할 수 있습니다. 예를 들어, has_cat연산자를 정의하고 목록에 원자가 포함되어 있는지 확인하기위한 술어로 정의합니다 cat.

:- op(500, xf, has_cat).
X has_cat :- member(cat, X).

?- [apple, cat, orange] has_cat.
true ;
false.

xf의미 has_cat는 접미사 연산자입니다. 를 사용 fx하면 접두사 연산자가되고 xfx두 개의 인수를 사용하여 접두사 연산자 가됩니다. Prolog에서 연산자 정의에 대한 자세한 내용은 이 링크 를 확인하십시오 .


5

TeX 가 완전히 누락되었습니다. 다들 알아? 다음과 같이 보입니다 :

Some {\it ``interesting''} example.

… 제한없이 구문을 재정의 할 수 있다는 점을 제외하고. 언어의 모든 (!) 토큰에 새로운 의미를 부여 할 수 있습니다. ConTeXt 는 중괄호를 대괄호로 대체 한 매크로 패키지입니다.

Some \it[``interesting''] example.

보다 일반적인 매크로 패키지 LaTeX\begin{environment}…\end{environment}구문 추가와 같은 목적으로 언어를 재정의 합니다.

그러나 거기서 멈추지 않습니다. 기술적으로 토큰을 재정 의하여 다음을 구문 분석 할 수 있습니다.

Some <it>“interesting”</it> example.

네, 물론 가능합니다. 일부 패키지는이를 사용하여 작은 도메인 별 언어를 정의합니다. 예를 들어, TikZ 패키지는 기술 도면에 대한 간결한 구문을 정의하여 다음을 허용합니다.

\foreach \angle in {0, 30, ..., 330} 
  \draw[line width=1pt] (\angle:0.82cm) -- (\angle:1cm);

또한 TeX는 Turing을 완료하여 문자 그대로 모든 것을 할 수 있습니다 . 나는 이것이 무의미하고 매우 복잡하기 때문에이 잠재력을 최대한 활용하는 것을 보지 못했지만 토큰을 재정 의하여 다음 코드를 구문 분석 할 수있게하는 것이 가능합니다 (그러나 아마도 파서의 물리적 한계로 갈 것입니다. 그것이 만들어진 방식) :

for word in [Some interesting example.]:
    if word == interesting:
        it(word)
    else:
        word

5

Boo를 사용하면 구문 분석 매크로를 통해 컴파일 타임에 언어를 크게 사용자 지정할 수 있습니다.

Boo에는 "확장 가능한 컴파일러 파이프 라인"이 있습니다. 즉, 컴파일러는 컴파일러 파이프 라인 동안 언제라도 AST 변환을 수행하기 위해 코드를 호출 할 수 있습니다. 아시다시피 Java의 Generics 또는 C #의 Linq와 같은 것은 컴파일 타임에 구문 변환 일 뿐이므로 매우 강력합니다.

Lisp와 비교할 때 가장 큰 장점은 모든 종류의 구문에서 작동한다는 것입니다. Boo는 Python에서 영감을 얻은 구문을 사용하고 있지만 C 또는 Pascal 구문으로 확장 가능한 컴파일러를 작성할 수 있습니다. 그리고 매크로는 컴파일 타임에 평가되므로 성능 저하가 없습니다.

Lisp에 비해 단점은 다음과 같습니다.

  • AST 작업은 s- 표현 작업보다 우아하지 않습니다.
  • 매크로는 컴파일 타임에 호출되므로 런타임 데이터에 액세스 할 수 없습니다.

예를 들어, 새로운 제어 구조를 구현하는 방법은 다음과 같습니다.

macro repeatLines(repeatCount as int, lines as string*):
    for line in lines:
        yield [| print $line * $repeatCount |]

용법:

repeatLines 2, "foo", "bar"

그런 다음 컴파일 타임에 다음과 같이 번역됩니다.

print "foo" * 2
print "bar" * 2

(불행히도 Boo의 온라인 문서는 항상 절망적으로 구식이며 이와 같은 고급 내용도 다루지 않습니다. 내가 아는 언어에 대한 최고의 문서는이 책입니다 : http://www.manning.com/rahien/ )


1
이 기능에 대한 웹 문서는 현재 망가졌으며 Boo를 직접 작성하지는 않았지만 간과하면 유감이라고 생각했습니다. 모드 피드백에 감사 드리며 여가 시간에 무료 정보를 제공하는 방법을 재고 할 것입니다.
Dan

4

평가 Mathematica 는 패턴 일치 및 대체를 기반으로합니다. 이를 통해 고유 한 제어 구조를 작성하거나 기존 제어 구조를 변경하거나 표현식 평가 방식을 변경할 수 있습니다. 예를 들어, 다음과 같이 "퍼지 로직"을 구현할 수 있습니다 (약간 단순화 됨).

fuzzy[a_ && b_]      := Min[fuzzy[a], fuzzy[b]]
fuzzy[a_ || b_]      := Max[fuzzy[a], fuzzy[b]]
fuzzy[!a_]           := 1-fuzzy[a]
If[fuzzy[a_], b_,c_] := fuzzy[a] * fuzzy[b] + fuzzy[!a] * fuzzy[c]

이는 사전 정의 된 논리 연산자 &&, || ,!의 평가를 대체합니다. 그리고 내장 If조항.

함수 정의와 같은 이러한 정의를 읽을 수 있지만 실제 의미는 다음과 같습니다. 표현식이 왼쪽에 설명 된 패턴과 일치하면 오른쪽에있는 표현식으로 바뀝니다. 다음과 같이 자신의 If-clause를 정의 할 수 있습니다.

myIf[True, then_, else_] := then
myIf[False, then_, else_] := else
SetAttributes[myIf, HoldRest]

SetAttributes[..., HoldRest] 평가자에게 패턴 일치 전에 첫 번째 인수를 평가해야하지만 패턴이 일치 및 교체 될 때까지 나머지에 대한 평가는 유지해야한다고 평가자에게 알려줍니다.

이것은 Mathematica 표준 라이브러리 내에서 광범위하게 사용되어 예를 들어 D표현을 취하고 상징적 미분으로 평가 되는 함수 를 정의합니다 .


3

Metalua 는 이것을 제공하는 언어와 Lua와 호환되는 컴파일러입니다.

  • Lua 5.1 소스 및 바이트 코드와의 완전한 호환성 : 깨끗하고 우아한 의미 및 구문, 놀라운 표현력, 우수한 성능, 거의 보편적 인 이식성. -리스프 (Lisp) 방언이나 템플릿 하스켈 (Template Haskell)의 기능과 유사한 완전한 매크로 시스템. 조작 된 프로그램은
    소스 코드, 추상 구문 트리 또는 임의의 조합 으로 볼 수 있습니다
    .
  • 동적으로 확장 가능한 파서로, 나머지 언어와 잘 어울리는 구문으로 매크로를 지원할 수 있습니다.

  • 일반 metalua 매크로로 구현 된 언어 확장 세트.

리스프와의 차이점 :

  • 개발자가 매크로를 작성하지 않을 때 매크로를 사용하지 마십시오. 언어의 구문과 의미는 매크로를 작성하지 않을 때의 95 %에 가장 적합해야합니다.
  • "모범 사례 rants"를 사용하는 사람뿐만 아니라 Metalua Way를 쉽게 작성할 수있는 API를 제공함으로써 개발자가 언어의 규칙을 따르도록 권장하십시오. 동료 개발자의 가독성은 컴파일러의 가독성보다 더 중요하고 달성하기가 더 어렵습니다.이를 위해 공통의 존중되는 규칙을 갖는 것이 많은 도움이됩니다.
  • 그러나 기꺼이 감당할 수있는 모든 힘을 제공하십시오. 루아와 메탈 루아 모두 강제적 인 속박과 훈련에 빠지지 않기 때문에 당신이하고있는 일을 안다면 언어는 방해가되지 않습니다.
  • 흥미로운 일이 생길 때, 모든 메타 오퍼레이션은 + {...}와-{...} 사이에서 발생하며, 일반적인 코드에서 시각적으로 튀어 나와야합니다.

적용의 예는 ML 유사 패턴 매칭의 구현이다.

참조 : http://lua-users.org/wiki/MetaLua


Lua는 실제로 Lisp이 아니지만 "차이"목록은 의심스러운 것입니다 (유일한 관련 항목이 마지막 항목 임). 물론 Lisp 커뮤니티는 매크로를 작성하거나 사용해서는 안된다는 동의에 동의하지 않을 것입니다-Lisp 방식은 매크로 대신에 DSL을 사용하고 작성하는 시간의 95 %와 같은 시간에 의존합니다. 코스.
SK-logic

2

확장 가능한 언어를 찾고 있다면 스몰 토크를 살펴 봐야합니다.

스몰 토크에서 프로그래밍 하는 유일한 방법 은 실제로 언어를 확장하는 것입니다. IDE, 라이브러리 또는 언어 자체에는 차이가 없습니다. 스몰 토크는 종종 언어 라기보다는 환경이라고 불릴 정도로 짝을 이룹니다.

Smalltalk에서 독립형 응용 프로그램을 작성하지 않고 언어 환경을 확장합니다.

소수의 리소스와 정보는 http://www.world.st/ 를 확인 하십시오.

스몰 토크의 세계로 들어가는 방언으로 Pharo를 추천하고 싶습니다 : http://pharo-project.org

그것이 도움이 되었기를 바랍니다!


1
흥미로운 것 같습니다.
Thomas Eding

1

전체 컴파일러를 처음부터 작성하지 않고도 사용자 지정 언어를 만들 수있는 도구가 있습니다. 예를 들어 코드 변환 도구 인 Spoofax 가 있습니다. 입력 문법과 변환 규칙 (매우 높은 수준의 선언적 방식으로 작성)을 입력 한 다음 Java 소스 코드 (또는 다른 언어, 충분히 신경 써야 할 경우)를 생성 할 수 있습니다 귀하가 디자인 한 맞춤 언어에서

따라서 언어 X의 문법을 취하고 언어 X '의 문법 (사용자 정의 확장명을 가진 X)과 변환 X'→ X를 정의 할 수 있으며 Spoofax는 컴파일러 X '→ X를 생성합니다.

현재 올바르게 이해하면 C # 지원이 개발되는 Java를 가장 잘 지원합니다. 이 기술은 정적 문법을 가진 모든 언어에 적용될 수 있습니다 (예를 들어 아마도 Perl이 아닙니다 ).


1

Forth 는 확장 성이 뛰어난 다른 언어입니다. 많은 Forth 구현은 어셈블러 또는 C로 작성된 작은 커널로 구성되며 나머지 언어는 Forth 자체로 작성됩니다.

Forth에서 영감을 얻어이 기능을 공유하는 여러 스택 기반 언어도 있습니다 (예 : Factor) .


0

펑지 -98

Funge-98의 지문 기능을 사용하면 언어의 전체 구문과 의미를 완전히 재구성 할 수 있습니다. 그러나 구현자가 사용자가 언어를 프로그래밍 방식으로 변경할 수있는 지문 메커니즘을 제공하는 경우에만 가능합니다 (이론적으로 일반적인 Funge-98 구문 및 의미 내에서 구현할 수 있습니다). 그렇다면 말 그대로 파일의 나머지 부분 (또는 파일의 모든 부분)을 C ++ 또는 Lisp (또는 원하는 항목)로 작동시킬 수 있습니다.

http://quadium.net/funge/spec98.html#Fingerprints


이전 답변 에 추가하지 않고 이것을 별도로 게시 했 습니까?
gnat

1
Funge는 Haskell과 아무 관련이 없기 때문입니다.
Thomas Eding

-1

찾고있는 것을 얻으려면 실제로 괄호와 구문이 필요하지 않습니다. 몇 가지 구문 기반 언어가 가까이있을 수 있지만 실제 매크로와는 다릅니다.

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