함수 언어로 컴파일러를 작성하는 것이 더 쉬운 이유는 무엇입니까? [닫은]


88

나는이 질문에 대해 오랫동안 생각해 왔지만 실제로 Stackoverflow에 대한 유사한 질문과 Google에서 답변을 찾을 수 없었습니다. 중복이 있으면 죄송합니다.

많은 사람들이 OCaml 및 Haskell과 같은 기능적 언어로 컴파일러 및 기타 언어 도구를 작성하는 것이 명령형 언어로 작성하는 것보다 훨씬 효율적이고 쉽다고 말하는 것 같습니다.

이것이 사실입니까? 그렇다면 C와 같은 명령형 언어 대신 기능적 언어로 작성하는 것이 왜 그렇게 효율적이고 쉬운가? 또한-기능적 언어의 언어 도구가 C와 같은 저수준 언어보다 느리지 않습니까?


5
더 쉽다고 말하지 않겠습니다. 그러나 파싱과 같은 컴파일 작업의 기능적 특성은 아마도 함수형 프로그래밍에 매우 자연스럽게 적합 할 것입니다. OCaml과 같은 기능적 언어는 C의 속도에 필적하는 매우 빠를 수 있습니다.
Robert Harvey

17
여러분,이게 정말 논쟁 적입니까? 분명히 누군가는 통찰력을 가지고 있습니다. 나 자신을 알고 싶습니다.
Robert Harvey

명령형 언어보다 기능적 언어를 사용하는 데에는 적어도 몇 가지 좋은 이유가 있어야한다고 생각합니다. 기본적으로 기능적 언어에는 부작용이 없다는 기사가 있습니다. 그러나 그것은 전혀 명확하지 않았습니다. 그러나 이것이 논쟁의 여지가 있다면 그것을 닫거나 질문을 재구성하는 것이 더 나을 수 있습니다.
wvd

12
일부 틈새 시장이 특정 언어 스타일에 더 적합하다는 것을 인정하는 것이 정말로 논쟁의 여지가 있습니까? "왜 C가 장치 드라이버를 작성하는 데 Javascript보다 나은 이유"는 논란의 여지가 없을 것입니다.
CA McCann

1
그 반대라고 생각했습니다. 나는 "초소형 컴파일러"를 읽고 있으며 모든 곳에서 변수 변이를 사용합니다.
Rolf

답변:


101

종종 컴파일러는 트리와 함께 많이 작동합니다. 소스 코드는 구문 트리로 구문 분석됩니다. 그런 다음 해당 트리는 유형 검사를 수행하기 위해 유형 주석이있는 다른 트리로 변환 될 수 있습니다. 이제 해당 트리를 핵심 언어 요소 만 포함하는 트리로 변환 할 수 있습니다 (구문 설탕과 같은 표기법을 승인되지 않은 형식으로 변환). 이제 기본적으로 트리에서 변환 인 다양한 최적화를 수행 할 수 있습니다. 그 후에는 일반적인 형태로 트리를 만든 다음 해당 트리를 반복하여 대상 (어셈블리) 코드를 만듭니다.

함수형 언어에는 패턴 일치와 같은 기능이 있고 효율적인 재귀를 지원하므로 트리 작업을 쉽게 할 수 있으므로 일반적으로 컴파일러 작성에 적합한 언어로 간주됩니다.


지금까지 가장 완전한 답변은 수락 된 답변으로 표시하겠습니다. 그러나 Pete Kirkham의 답변도 좋은 것 같습니다.
wvd

1
컴파일러의 정확성이 중요한 속성이기 때문에 "정확성 제공"은 어떻습니까? 함수형 언어의 팬들이 어떻게 든 워크 플로에 정확성의 "증명"을 통합한다는 말을 자주 들었습니다. 이것이 실제적으로 어떤 의미인지는 모르겠지만 컴파일러 신뢰성이 중요하기 때문에 가치가있는 것 같습니다.
Warren P

3
@WarrenP : "증거 코드"개념은 정적으로 형식화 된 함수 언어에서 비롯됩니다. 아이디어는 함수가 올바른 경우에만 유형 검사를 할 수 있도록 유형 시스템을 사용하는 것이므로 코드가 컴파일된다는 사실이 정확성의 증거입니다. 물론 이것은 언어 튜링을 완전하게 유지하고 유형 검사를 결정 가능한 상태로 유지하면서 완전히 가능하지는 않습니다. 그러나 유형 시스템이 강할수록 그 목표에 더 가까워 질 수 있습니다.
sepp2k

3
이 개념이 함수 커뮤니티에서 주로 인기있는 이유는 변경 가능한 상태가있는 언어에서 유형에서 상태 변경이 발생하는시기와 위치에 대한 정보를 인코딩해야하기 때문입니다. 함수의 결과가 인수에만 의존한다는 것을 알고있는 언어에서는 유형으로 증명을 인코딩하는 것이 훨씬 더 쉽습니다 (또한 전역 상태를 고려할 필요가 없기 때문에 코드의 정확성을 수동으로 증명하는 것이 훨씬 더 쉽습니다.) 가능하고 기능의 동작에 어떻게 영향을 미치는지). 그러나 이것 중 어느 것도 컴파일러와 특별히 관련이 없습니다.
sepp2k

3
가장 중요한 기능은 제 생각에 패턴 매칭입니다. 패턴 매칭으로 추상 구문 트리를 최적화하는 것은 어리석은 일입니다. 패턴 매칭없이 수행하는 것은 종종 매우 어렵습니다.
Bob Aman

38

많은 컴파일러 작업은 트리 구조에서 패턴 일치입니다.

OCaml과 Haskell은 모두 강력하고 간결한 패턴 매칭 기능을 가지고 있습니다.

패턴을 일치시키기 위해 평가되거나 추출되는 값은 부작용이 없어야하므로 명령형 언어에 패턴 일치를 추가하기가 더 어렵습니다.


합리적인 대답처럼 들리지만 이것이 유일한 것입니까? 예를 들어 꼬리 재귀와 같은 것도 역할을할까요?
wvd

그것은 실제 실행 모델보다 유형 시스템의 문제에 더 가깝다는 것을 나타내는 것 같습니다. 구조적 유형에 대해 변경 불가능한 값이있는 명령형 프로그래밍을 기반으로하는 것이 괜찮을 수 있습니다.
Donal Fellows

@wvd : 테일 재귀 최적화는 언어 기능이 아닌 구현 세부 사항으로, 선형 재귀 함수를 반복 루프와 동일하게 만듭니다. C에서 연결된 목록을 탐색하는 재귀 함수는 Scheme의 목록에서 반복하는 것과 마찬가지로 이점을 얻을 수 있습니다.
CA McCann

@wvd gcc C는 다른 가변 상태 언어와 마찬가지로 테일 콜 제거 기능을 제공합니다
Pete Kirkham

3
@camccann : 언어 표준이 tco를 보장하는 경우 (또는 적어도 특정 형식의 재귀 함수가 스택 오버플로 또는 메모리 소비의 선형 증가를 유발하지 않음을 보장), 저는 언어 기능이라고 생각합니다. 표준이 그것을 보장하지 않지만 컴파일러가 어쨌든 그것을 보장한다면 그것은 컴파일러 기능입니다.
sepp2k

15

고려해야 할 중요한 요소 중 하나는 컴파일러 프로젝트의 큰 부분이 컴파일러를 자체 호스팅하고 "자신의 개 사료를 먹을"수 있다는 것입니다. 이러한 이유로 언어 연구를 위해 설계된 OCaml과 같은 언어를 살펴보면 컴파일러 유형 문제에 대한 훌륭한 기능을 갖는 경향이 있습니다.

저의 마지막 컴파일러 작업에서 우리는 C 코드를 조작하는 동안 정확히 이런 이유로 OCaml을 사용했습니다.이 작업에 가장 적합한 도구였습니다. INRIA의 사람들이 우선 순위가 다른 OCaml을 구축했다면 그다지 적합하지 않았을 것입니다.

즉, 기능적 언어는 모든 문제를 해결하는 데 가장 좋은 도구이므로 논리적으로이 특정 문제를 해결하는 데 가장 좋은 도구입니다. QED.

/ me : 내 Java 작업으로 조금 덜 즐겁게 크롤링합니다 ...


4
-1 : "기능적 언어는 모든 문제를 해결하는 가장 좋은 도구입니다." 이것이 사실이라면 우리 모두는 모든 곳에서 사용할 것입니다. ;)
Andrei Krotkov

15
@Andrei Krotkov : 오늘의 단어는 fa · ce · tious입니다 발음 : \ fə-ˈsē-shəs \ 기능 : 형용사 어원 : 중세 프랑스어 facetieux, from facetie jest, from Latin facetia 날짜 : 1599 1 : 농담이나 농담 자주 부적절하게 : waggish <그냥 우스꽝스러워> 2 : 유머러스하거나 웃기다 : 진지하지 않음 <a facetious remark> 동의어 see witty 농담을 놓치는 것 외에도 논리는 여전히 결함이 있습니다. 당신은 모든 사람들이 이성적인 배우라고 가정하고 있고, 제가 두려워하는 것은 공정한 가정이 아닙니다.
Ukko

5
나는 완전히 진지한 것을 제외하고는 거의 정확한 말을 할 실제 사람들을 알고 있기 때문에 농담을 놓친 것 같습니다. 포의 법칙 이군요. tvtropes.org/pmwiki/pmwiki.php/Main/PoesLaw
Andrei Krotkov

13
@Andrei : 당신의 주장 광고 팝업 사용 : "이성이 감정적 인 무지보다 낫다면, 우리 모두는 그것을 모든 곳에서 사용할 것입니다."
Tim Schaeffer

9

기본적으로 컴파일러는 소스에서 IR로, IR에서 최적화 된 IR로, IR에서 어셈블리로 등 한 세트의 코드에서 다른 코드 세트로의 변환입니다. 이것은 정확히 함수 언어가 설계된 것과 같은 종류입니다. 한 가지에서 다른 것으로의 변화 일뿐입니다. 명령형 함수에는 이러한 품질이 없습니다. 명령형 언어로 이런 종류의 코드를 작성할 수 있지만 기능적 언어는이를 위해 특화되어 있습니다.


6

또한보십시오

F # 디자인 패턴

FP는 사물을 '작업별로'그룹화하는 반면, OO는 사물을 '유형별로'그룹화하며, '작업 별'은 컴파일러 / 인터프리터에 더 자연 스럽습니다.


3
이것은 일부 프로그래밍 언어 이론 서클에서 "표현 문제"라고 불리는 것과 관련이 있습니다. 예를 들어, "확장 가능한 유형"방식으로 작업을 수행하는 정말 끔찍한 Haskell 코드를 보여주는 이 질문을 참조하십시오 . 반대로, OOP 언어를 "확장 가능한 작업"스타일로 강제하는 것은 방문자 패턴에 동기를 부여하는 경향이 있습니다.
CA McCann

6

한 가지 가능성은 컴파일러가 수많은 코너 케이스를 매우 신중하게 처리해야하는 경향이 있다는 것입니다. 구현하는 규칙과 유사한 방식으로 구현을 구조화하는 디자인 패턴을 사용하면 코드를 올바르게 가져 오는 것이 더 쉬워집니다. 종종 그것은 명령 적 (시퀀싱, "언제") 디자인이 아닌 선언적 (패턴 매칭, "where") 디자인이되어 선언적 언어로 구현하기가 더 쉽습니다 (그리고 대부분 기능적입니다).


4

모두가 또 다른 중요한 이유를 놓친 것 같습니다. 일반 코드에서 (E) BNF와 매우 유사한 파서 용 임베디드 도메인 특정 언어 (EDSL)를 작성하는 것은 매우 쉽습니다. Parsec과 같은 파서 결합 자는 고차 함수 및 함수 구성을 사용하여 함수 언어로 작성하기가 매우 쉽습니다. 더 쉬울뿐만 아니라 매우 우아하게.

기본적으로 가장 단순한 일반 파서를 함수로 표현하고 이러한 기본 파서를 문법에 대한 더 복잡하고 구체적인 파서로 구성 할 수있는 특수 작업 (일반적으로 고차 함수)이 있습니다 .

이것은 과정의 프레임 워크를 분석하는 유일한 방법은 아닙니다.

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