이 답변은 illissius가 제기 한 문제에 대한 답변입니다.
- 사용하기 싫습니다. $ (fooBar ''Asdf)는 멋지게 보이지 않습니다. 피상적이지만 확실히 기여합니다.
나는 동의한다. 나는 Haskell의 친숙한 기호 팔레트를 사용하여 $ ()가 언어의 일부인 것처럼 보이도록 선택되었다고 생각합니다. 그러나, 매크로 스 플라이 싱에 사용되는 심볼에서 정확히 원하지 않는 것입니다. 그들은 너무 많이 섞여 있으며,이 미용 측면은 매우 중요합니다. 나는 시각적으로 뚜렷하기 때문에 스플 라이스의 {{}} 모양을 좋아합니다.
- 쓰기가 더 나쁘다. 인용은 때때로 작동하지만 수동 AST 접목 및 배관 작업을 수행해야하는 경우가 많습니다. [API] [1]은 크고 다루기 힘들며, 항상 신경 쓰지 않지만 파견해야 할 경우가 많으며, 신경 쓰인 경우는 여러 가지 유사하지만 동일한 형태가 아닌 경향이 있습니다 (데이터 대 newtype, 레코드 스타일 대 일반 생성자 등). 쓰기가 지루하고 반복적이며 기계적이지 않을 정도로 복잡합니다. [개혁 제안] [2]는이 중 일부를 언급한다 (견적을 더 널리 적용 가능하게 함).
그러나 "TH의 새로운 방향"에 나오는 일부 의견에서 알 수 있듯이, 즉시 사용할 수있는 AST 인용의 부족이 중요한 결점이 아닙니다. 이 WIP 패키지에서는 https://github.com/mgsloan/quasi-extras 라이브러리 형식으로 이러한 문제를 해결하려고합니다 . 지금까지 평소보다 몇 곳 더 접합 할 수 있으며 AST에서 패턴 일치를 할 수 있습니다.
- 무대 제한은 지옥입니다. 동일한 모듈에 정의 된 함수를 스플 라이스 할 수없는 것은 그 중 작은 부분입니다. 다른 결과는 최상위 스플 라이스가있는 경우 모듈에서 그 뒤에있는 모든 것이 범위를 벗어납니다. 이 속성 (C, C ++)을 가진 다른 언어는 선언을 전달할 수있게 해주지 만 하스켈은 그렇지 않습니다. 스 플라이 싱 된 선언 또는 그 종속 항목과 종속 항목 사이에 순환 참조가 필요한 경우 일반적으로 문제가 있습니다.
이전에 순환 TH 정의가 불가능하다는 문제에 부딪 쳤습니다. 상당히 성가신 일입니다. 해결책이 있지만 추악한 것입니다. 순환 종속성과 관련된 사항을 생성 된 모든 선언을 결합하는 TH 식으로 래핑하십시오. 이러한 선언 중 하나는 Haskell 코드를 받아들이는 준 인용 부호 일 수 있습니다.
- 원칙이 아닙니다. 이것이 의미하는 바는 대부분 추상화를 표현할 때 그 추상화 뒤에 어떤 원리 나 개념이 있다는 것입니다. 많은 추상화에서, 그 뒤에있는 원리는 유형으로 표현 될 수 있습니다. 유형 클래스를 정의 할 때, 어떤 인스턴스가 준수해야하고 클라이언트가 가정 할 수있는 법률을 공식화 할 수 있습니다. GHC의 [새로운 제네릭 기능] [3]을 사용하여 (한도 내에서) 모든 데이터 유형에 대한 인스턴스 선언 형식을 추상화하면 "합계 유형의 경우 제품 유형의 경우 다음과 같이 작동합니다. ". 그러나 템플릿 Haskell은 단순한 매크로입니다. 아이디어 수준의 추상화가 아니라 AST 수준의 추상화입니다. 일반 텍스트 수준의 추상화보다 낫지 만 겸손합니다.
원칙을 세우지 않은 경우에만 원칙이 적용되지 않습니다. 유일한 차이점은 컴파일러가 추상화를위한 메커니즘을 구현하면 추상화가 유출되지 않는다는 확신이 더 커진다는 것입니다. 아마도 언어 디자인을 민주화하는 것은 약간 무섭게 들립니다! TH 라이브러리의 제작자는 문서를 잘 문서화하고 제공하는 도구의 의미와 결과를 명확하게 정의해야합니다. 원칙 TH의 좋은 예는 파생 패키지 : http://hackage.haskell.org/package/derive - 이는 DSL을 사용하도록 유도 / 지정 / 실제 유도 다수의 예.
- GHC에 연결됩니다. 이론적으로 다른 컴파일러가 그것을 구현할 수는 있지만 실제로는 이것이 일어날 것이라고 의심합니다. (이것은 현재 GHC에 의해서만 구현 될 수 있지만 다양한 컴파일러가 확장되어 다른 컴파일러에 의해 채택되고 결국 표준화되는 것을 쉽게 상상할 수 있습니다.)
TH API는 꽤 크고 복잡합니다. 다시 구현하면 힘들 수 있습니다. 그러나 Haskell AST를 나타내는 문제를 해결하는 방법은 실제로 몇 가지뿐입니다. TH ADT를 복사하고 내부 AST 표현에 변환기를 작성하면 많은 도움이 될 것입니다. 이것은 haskell-src-meta를 만드는 (의의하지 않은) 노력과 동등합니다. TH AST를 예쁘게 인쇄하고 컴파일러의 내부 파서를 사용하여 간단하게 다시 구현할 수도 있습니다.
내가 틀릴 수는 있지만 TH는 구현 관점에서 컴파일러 확장이 복잡하다고 생각하지 않습니다. 이것은 실제로 "단순하게 유지"하는 이점 중 하나이며 기본 계층이 이론적으로 매력적이고 정적으로 검증 가능한 템플릿 시스템이되지는 않습니다.
- API가 안정적이지 않습니다. 새로운 언어 기능이 GHC에 추가되고이를 지원하기 위해 template-haskell 패키지가 업데이트 될 때 TH 데이터 유형에 대해 이전 버전과 호환되지 않는 변경이 종종 발생합니다. TH 코드가 여러 버전의 GHC와 호환되도록하려면 매우주의해서 사용해야
CPP
합니다.
이것은 또한 좋은 지적이지만 다소 극적입니다. 최근 API 추가가 있었지만 전반적으로 중단을 유발하지는 않았습니다. 또한 앞에서 언급 한 우수한 AST 인용을 통해 실제로 사용해야하는 API를 크게 줄일 수 있다고 생각합니다. 구성 / 일치에 고유 한 기능이 필요하지 않고 리터럴로 표현되면 대부분의 API가 사라집니다. 또한 작성한 코드는 Haskell과 유사한 언어의 AST 표현으로 더 쉽게 이식됩니다.
요약하면 TH는 강력하고 반 무시 된 도구라고 생각합니다. 증오가 적을수록 더욱 생생한 도서관 생태계가 생겨 더 많은 언어 기능 프로토 타입을 구현할 수 있습니다. TH는 강력한 도구이므로 거의 모든 작업을 수행 할 수 있습니다. 무정부 상태! 글쎄,이 능력을 통해 대부분의 한계를 극복하고 상당히 체계적인 메타 프로그래밍 방식이 가능한 시스템을 만들 수 있다고 생각합니다. "적절한"구현의 디자인이 점차 명확 해 지므로 "적절한"구현을 시뮬레이션하기 위해 추악한 해킹을 사용할 가치가 있습니다.
개인적으로 이상적인 너바나 버전에서 대부분의 언어는 실제로 컴파일러에서 이러한 다양한 라이브러리로 이동합니다. 기능이 라이브러리로 구현된다는 사실은 충실하게 추상화하는 기능에 큰 영향을 미치지 않습니다.
상용구 코드에 대한 일반적인 Haskell의 답변은 무엇입니까? 추출. 우리가 가장 좋아하는 추상화는 무엇입니까? 함수와 타입 클래스!
타입 클래스를 사용하면 메소드 세트를 정의 할 수 있으며, 그런 다음 해당 클래스에서 일반적인 모든 방식의 함수에 사용할 수 있습니다. 그러나이 외에도 클래스가 상용구를 피하는 유일한 방법은 "기본 정의"를 제공하는 것입니다. 다음은 원칙에 맞지 않는 기능의 예입니다!
TH와 lisp와 같은 메타 프로그래밍을 거부하면 인스턴스 선언과 같이보다 유연하고 매크로 확장이 아닌 메소드 기본값과 같은 것을 선호한다고 생각합니다. 예상치 못한 결과를 초래할 수있는 것들을 피하는 원칙은 현명하지만, 우리는 Haskell의 유능한 유형 시스템이 다른 많은 환경보다 (생성 된 코드를 검사함으로써)보다 안정적인 메타 프로그래밍을 허용한다는 것을 무시해서는 안됩니다.