Haskell에서 Haskell 인터프리터 작성


90

고전적인 프로그래밍 연습은 Lisp / Scheme에서 Lisp / Scheme 인터프리터를 작성하는 것입니다. 전체 언어의 힘을 활용하여 언어의 하위 집합에 대한 인터프리터를 생성 할 수 있습니다.

Haskell에 대한 유사한 운동이 있습니까? Haskell을 엔진으로 사용하여 Haskell의 하위 집합을 구현하고 싶습니다. 물론 할 있지만 볼 수있는 온라인 리소스가 있습니까?


여기 뒷이야기가 있습니다.

저는 제가 가르치고 있는 이산 구조 과정의 일부 개념을 탐구하기 위해 Haskell을 언어로 사용하는 아이디어를 탐구하고 있습니다 . 이번 학기 동안 저는 Haskell에 영감을 준 작은 언어 인 Miranda에 정착했습니다 . Miranda는 내가 원하는 작업의 약 90 %를 수행하지만 Haskell은 약 2000 %를 수행합니다. :)

그래서 내 생각은 내가 원하고 다른 모든 것을 허용하지 않는 Haskell의 기능을 정확히 가진 언어를 만드는 것입니다. 학생들이 발전함에 따라 기본 사항을 익히면 다양한 기능을 선택적으로 "켜기"수 있습니다.

JavaScheme 을 가르치는 데 교육 학적 "언어 수준"이 성공적으로 사용되었습니다 . 그들이 할 수있는 일을 제한함으로써, 그들이 가르치려고하는 구문과 개념을 마스터하는 동안 그들이 스스로 발을 쏘는 것을 방지 할 수 있습니다. 또한 더 나은 오류 메시지를 제공 할 수 있습니다.


Haskell의 Typing Haskell을 기반으로 구현 된 WIP Haskell 방언이 있습니다. 여기에 데모가 있습니다. chrisdone.com/toys/duet-delta 공개 오픈 소스 릴리스 준비가되지 않았지만 관심이 있다면 소스를 공유 할 수 있습니다.
Christopher Done

답변:


76

나는 당신의 목표를 사랑하지만 그것은 큰 일입니다. 몇 가지 힌트 :

  • 나는 GHC에서 일했고 당신은 소스의 어떤 부분도 원하지 않습니다. Hugs 는 훨씬 간단하고 깔끔한 구현이지만 안타깝게도 C에 있습니다.

  • 그것은 퍼즐의 작은 조각이지만 Mark Jones는 Haskell에서 Typing Haskell 이라는 아름다운 논문을 썼습니다. 이것은 당신의 프론트 엔드를위한 훌륭한 출발점이 될 것입니다.

행운을 빕니다! 교실에서 얻은 증거와 함께 Haskell의 언어 수준을 식별하는 것은 커뮤니티에 큰 도움이되며 확실히 게시 가능한 결과입니다!


2
GHC에 대한 의견이 여전히 정확한지 궁금합니다. GHC는 복잡하지만 매우 잘 문서화되어 있습니다. 특히 내부 Notes는 낮은 수준의 세부 사항을 이해하는 데 도움이되며 오픈 소스 응용 프로그램의 아키텍처 에서 GHC에 대한 장에서는 뛰어난 수준의 개요를 제공합니다.
sjy 2014 년

37

완전한 Haskell 파서가 있습니다 : http://hackage.haskell.org/package/haskell-src-exts

일단 파싱하면 특정 항목을 제거하거나 허용하지 않는 것이 쉽습니다. 나는 tryhaskell.org에서 import 문을 허용하지 않고 최상위 정의를 지원하는 등의 작업을 수행했습니다.

모듈을 구문 분석하십시오.

parseModule :: String -> ParseResult Module

그런 다음 모듈에 대한 AST가 있습니다.

Module SrcLoc ModuleName [ModulePragma] (Maybe WarningText) (Maybe [ExportSpec]) [ImportDecl] [Decl]    

Decl 유형은 광범위합니다 : http://hackage.haskell.org/packages/archive/haskell-src-exts/1.9.0/doc/html/Language-Haskell-Exts-Syntax.html#t%3ADecl

여러분이해야 할 일은 선언, 임포트, 심볼, 구문을 사용할 수있는 화이트리스트를 정의한 다음 AST를 살펴보고 아직 알기를 원하지 않는 항목에 대해 "파싱 오류"를 발생시키는 것입니다. AST의 모든 노드에 연결된 SrcLoc 값을 사용할 수 있습니다.

data SrcLoc = SrcLoc
     { srcFilename :: String
     , srcLine :: Int
     , srcColumn :: Int
     }

Haskell을 다시 구현할 필요가 없습니다. 보다 친숙한 컴파일 오류를 제공하려면 코드를 구문 분석하고 필터링 한 다음 컴파일러로 전송하고 컴파일러 출력을 구문 분석하면됩니다. "추론 된 유형에 대해 예상 유형 a와 일치 할 수 없음"인 경우 a -> b함수에 대한 인수가 너무 적다는 것을 알 수 있습니다.

실제로 Haskell을 처음부터 구현하거나 Hugs의 내부 또는 멍청한 구현을 엉망으로 만드는 데 시간을 소비하고 싶지 않다면 GHC로 전달되는 것을 필터링해야한다고 생각합니다. 이렇게하면 학생들이 코드 기반을 가져 와서 다음 단계로 이동하여 완전한 Haskell 코드를 작성하려는 경우 전환이 투명합니다.


24

통역사를 처음부터 만들고 싶습니까? 람다 미적분 또는 lisp 변형과 같은 더 쉬운 기능적 언어를 구현하는 것으로 시작하십시오. 후자의 경우 구문 분석 및 해석 기술에 대한 멋지고 실용적인 소개를 제공하는 Write yourself a Scheme 이라는 아주 멋진 위키 북이 있습니다.

하스켈을 손으로 해석하는 것은 타입 클래스, 매우 강력한 타입 시스템 (타입 추론!), 지연 평가 (감소 기술)와 같은 매우 복잡한 기능을 다루어야하기 때문에 훨씬 더 복잡 할 것입니다.

따라서 작업 할 Haskell의 아주 작은 하위 집합을 정의한 다음 Scheme-example을 단계적으로 확장하여 시작할 수 있습니다.

부가:

Haskell에서는 파서, 컴파일러 및 물론 인터프리터를 포함하여 인터프리터 API (적어도 GHC에서)에 대한 전체 액세스 권한이 있습니다.

사용할 패키지는 hint (Language.Haskell. *) 입니다. 나는 불행히도 이것에 대한 온라인 튜토리얼을 찾지 못했고 혼자서 시도하지 않았지만 꽤 유망 해 보입니다.


12
유형 추론은 실제로 정말 쉬운 20-30 라인 알고리즘입니다. 단순함이 아름답습니다. 지연 평가도 인코딩하기 어렵지 않습니다. 난이도가 미친 구문, 패턴 매칭, 언어의 많은 양에 있다고 말하고 싶습니다.
Claudiu

흥미 롭다-타입 추론 알고리즘에 대한 링크를 게시 할 수 있습니까?
Dario

5
예,이 무료 책을 확인하십시오 -cs.brown.edu/~sk/Publications/Books/ProgLangs/2007-04-26- , 273 페이지 (pdf의 289)에 있습니다. alg 의사 코드는 P296에 있습니다.
Claudiu

1
" The Implementation of Functional Programming Languages "에 (the?) 유형 추론 / 검사 알고리즘 의 구현도 있습니다.
Phil Armstrong

1
그러나 유형 클래스를 사용한 유형 추론은 간단하지 않습니다.
Christopher Done

20

내가 원하고 다른 모든 것을 허용하지 않는 Haskell의 기능을 정확히 가진 언어를 만듭니다. 학생들이 발전함에 따라 기본 사항을 익히면 다양한 기능을 선택적으로 "켜기"수 있습니다.

이 문제에 대한 더 간단한 해결책을 제안합니다. 기능을 끌 수있는 Haskell 구현을 만드는 대신 코드가 허용하지 않는 기능을 사용하지 않는지 먼저 확인하는 프로그램으로 Haskell 컴파일러를 래핑 한 다음 미리 만들어진 컴파일러를 사용하여 컴파일합니다.

이는 HLint 와 유사합니다 (또한 그 반대입니다).

HLint (이전의 Dr. Haskell)는 Haskell 프로그램을 읽고 쉽게 읽을 수있는 변경 사항을 제안합니다. HLint를 사용하면 원하지 않는 제안을 쉽게 비활성화하고 사용자 지정 제안을 추가 할 수 있습니다.

  • 허용하지 않는 기능을 사용하지 않도록 자신의 HLint "제안"을 구현하십시오.
  • 모든 표준 HLint 제안을 비활성화합니다.
  • 래퍼가 수정 된 HLint를 첫 번째 단계로 실행하도록합니다.
  • HLint 제안을 오류로 처리합니다. 즉, HLint가 "불만"하면 프로그램이 컴파일 단계로 진행되지 않습니다.


6

EHC 시리즈 컴파일러는 아마도 최선의 선택 일 것입니다 : 그것은 적극적으로 개발되었고 정확히 당신이 원하는 것처럼 보입니다.-Haskell '98에서 절정에 달하는 일련의 작은 람다 미적분 컴파일러 / 통역사입니다.

그러나 Pierce의 유형 및 프로그래밍 언어 또는 헬륨 인터프리터 (학생들을위한 장애가있는 Haskell http://en.wikipedia.org/wiki/Helium_(Haskell) ) 에서 개발 된 다양한 언어를 볼 수도 있습니다 .


6

구현하기 쉬운 Haskell의 하위 집합을 찾고 있다면 유형 클래스 및 유형 검사를 제거 할 수 있습니다. 유형 클래스가 없으면 Haskell 코드를 평가하기 위해 유형 추론이 필요하지 않습니다.

저는 Code Golf 챌린지를 위해 자체 컴파일하는 Haskell 하위 집합 컴파일러작성 했습니다. 입력시 Haskell 하위 집합 코드를 사용하고 출력시 C 코드를 생성합니다. 더 읽기 쉬운 버전이 없어서 죄송합니다. 자체 컴파일하는 과정에서 중첩 된 정의를 직접 해제했습니다.

Haskell의 하위 집합에 대한 인터프리터를 구현하는 데 관심이있는 학생의 경우 다음 기능으로 시작하는 것이 좋습니다.

  • 게으른 평가. 인터프리터가 Haskell에 있으면이를 위해 아무것도 할 필요가 없습니다.

  • 패턴 일치 인수 및 가드가있는 함수 정의. 변수, 단점, nil 및 _패턴 에 대해서만 걱정하십시오 .

  • 간단한 표현식 구문 :

    • 정수 리터럴

    • 문자 리터럴

    • [] (무)

    • 기능 적용 (왼쪽 연관)

    • 중위 :(단점, 오른쪽 연관)

    • 괄호

    • 변수 이름

    • 기능 명

더 구체적으로, 이것을 실행할 수있는 인터프리터를 작성하십시오.

-- tail :: [a] -> [a]
tail (_:xs) = xs

-- append :: [a] -> [a] -> [a]
append []     ys = ys
append (x:xs) ys = x : append xs ys

-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f (a:as) (b:bs) = f a b : zipWith f as bs
zipWith _ _      _      = []

-- showList :: (a -> String) -> [a] -> String
showList _    []     = '[' : ']' : []
showList show (x:xs) = '[' : append (show x) (showItems show xs)

-- showItems :: (a -> String) -> [a] -> String
showItems show []     = ']' : []
showItems show (x:xs) = ',' : append (show x) (showItems show xs)

-- fibs :: [Int]
fibs = 0 : 1 : zipWith add fibs (tail fibs)

-- main :: String
main = showList showInt (take 40 fibs)

유형 검사는 Haskell의 중요한 기능입니다. 그러나 무에서 타입 검사 하스켈 컴파일러로가는 것은 매우 어렵습니다. 위의 인터프리터를 작성하여 시작하는 경우 유형 검사를 추가하는 것이 덜 어렵습니다.


"지연 평가. 인터프리터가 Haskell에있는 경우이를 위해 아무것도 할 필요가 없습니다." 이것은 사실이 아닐 수 있습니다. Haskell에서 게으른 인터프리터를 구현하는 방법에 대한 자세한 내용은 haskell.org/wikiupload/0/0a/TMR-Issue10.pdf 에 있는 Naylor의 기사를 참조하십시오 .
Jared Updike 2014 년


3

이것은 좋은 생각 일 수 있습니다-하스켈에서 NetLogo의 작은 버전을 만드십시오. 여기 작은 통역사가 있습니다.


링크가 끊어졌습니다. 이 콘텐츠가 여전히 다른 곳에 존재할 가능성이 있습니까? 나는 ... 싶은데요
니콜라스 호 Payette

흠 그것은 블로그 게시물이었고 그것을 검색하기 위해 어떤 키워드를 사용 해야할지 모르겠습니다. ... 링크를 제공 할 때 좋은 교훈은 더 실질적인 정보를 포함하는
Claudiu

1
"netlogo haskell"에 대한 Google 검색이 나타납니다.이 질문입니다. 어쨌든 별거 아니야. 감사!
Nicolas Payette 2012



2

나는 Idris 가 상당히 콤팩트 한 파서를 가지고 있다고 들었는데 , 그것이 정말로 변경에 적합한 지 확실하지 않지만 Haskell로 작성되었습니다.


2

Andrej Bauer의 Programming Language Zoo 는 "minihaskell"이라는 이름의 순전히 기능적인 프로그래밍 언어의 작은 구현을 가지고 있습니다. 약 700 줄의 OCaml이므로 소화하기 매우 쉽습니다.

이 사이트에는 ML 스타일, 프롤로그 스타일 및 OO 프로그래밍 언어의 장난감 버전도 포함되어 있습니다.


1

처음부터 자신의 Haskell 인터프리터를 작성하는 것보다 GHC 소스 를 가져와 원하지 않는 것을 제거하는 것이 더 쉬울 것이라고 생각 하지 않습니까? 일반적으로 기능을 생성 / 추가 하는 것보다 기능을 제거하는 데 드는 노력 이 훨씬 적어야 합니다.

GHC는 어쨌든 Haskell로 작성되었으므로 기술적으로 Haskell로 작성된 Haskell 인터프리터에 대한 질문에 남아 있습니다.

모든 것을 정적으로 연결 한 다음 사용자 정의 된 GHCi 만 배포하여 학생들이 다른 Haskell 소스 모듈을로드 할 수 없도록하는 것이 그리 어렵지 않을 것입니다. 다른 Haskell 개체 파일을로드하지 못하도록하는 데 얼마나 많은 작업이 필요한지에 대해서는 모르겠습니다. 수업에 사기꾼이 많으면 FFI를 비활성화하고 싶을 수도 있습니다. :)


1
많은 기능이 다른 기능에 의존하기 때문에 이것은 들리는 것처럼 쉽지 않습니다. 그러나 아마도 OP는 Prelude를 가져 오지 않고 대신 자신의 것을 제공하기를 원할 것입니다. 여러분이 보는 대부분의 Haskell은 런타임의 특정 기능이 아니라 일반 기능입니다. (물론 많이 있습니다 .)
jrockway

0

LISP 인터프리터가 많은 이유는 LISP가 기본적으로 데이터를 인코딩하는 간단한 형식 인 JSON의 이전 버전이기 때문입니다. 이렇게하면 프런트 엔드 부분을 매우 쉽게 처리 할 수 ​​있습니다. 이에 비해 Haskell, 특히 Language Extensions는 구문 분석하기 가장 쉬운 언어가 아닙니다. 다음은 제대로 이해하기 어렵게 들리는 몇 가지 구문 구조입니다.

  • 구성 가능한 우선 순위, 연관성 및 고 정성을 가진 연산자,
  • 중첩 된 주석
  • 레이아웃 규칙
  • 패턴 구문
  • do-모나 딕 코드로 블록 및 탈당

운영자를 제외한 각각은 컴파일러 구성 과정을 마친 후 학생들이 다룰 수 있지만 Haskell이 실제로 작동하는 방식에서 초점을 잃을 것입니다. 그 외에도 Haskell의 모든 구문 구조를 직접 구현하지 않고 대신 패스를 구현하여 제거 할 수 있습니다. 이것은 우리를 완전히 의도 된 말장난으로 문제의 문자 그대로 핵심으로 안내합니다.

내 제안은 Core전체 Haskell 대신 typechecking과 인터프리터를 구현하는 것입니다. 이 두 작업은 이미 그 자체로 매우 복잡합니다. 이 언어는 여전히 강력한 유형의 기능적 언어이지만 최적화 및 코드 생성 측면에서 다루기가 훨씬 덜 복잡합니다. 그러나 여전히 기본 시스템과는 독립적입니다. 따라서 GHC는이를 중개 언어로 사용하고 대부분의 하스켈 구문 구조를이 언어로 번역합니다.

또한 GHC (또는 다른 컴파일러)의 프런트 엔드를 사용하는 것을 주저해서는 안됩니다. 사용자 지정 LISP가 호스트 LISP 시스템의 파서를 사용하기 때문에 부정 행위로 간주하지 않습니다 (적어도 부트 스트랩 중). Core스 니펫을 정리 하고 원래 코드와 함께 학생들에게 제시하면 프런트 엔드가 수행하는 작업과이를 다시 구현하지 않는 것이 바람직한 이유에 대한 개요를 제공 할 수 있습니다.

다음은 CoreGHC에서 사용되는 문서에 대한 몇 가지 링크입니다 .

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