テンプレートHaskellの何が悪いのですか?


252

テンプレートHaskellは、Haskellコミュニティから不幸な便宜と見なされることが多いようです。これに関して私が観察したことを正確に言葉にするのは難しいですが、これらのいくつかの例を検討してください

私は、人々がテンプレートHaskellでかなりきちんとしたことをするさまざまなブログ投稿を見てきました。では、なぜテンプレートHaskellがこのように軽視されているのでしょうか。何が望ましくないのですか?テンプレートHaskellはどのような状況で避けなければならないのですか、そしてその理由は何ですか?


56
私は移動する投票に同意しません。私は私が尋ねたのと同じ精神でこの質問をしています。レイジーI / Oの何が悪いのですか?と私は同じファッションの答えを見ることを期待しています。それが役立つ場合は、質問を言い換えることができます。
Dan Burton、2012年

51
@ErikPhilipsこのタグに頻繁にアクセスする人々に、このタグがここに属しているかどうかを判断させてみませんか?Haskellコミュニティとのあなたの唯一の相互作用はその質問を書くことであるようです。
Gabriel Gonzalez

5
@GabrielGonzalezそれが現在の質問と回答で明らかであるので、ここでは質問しないでくださいどのような種類の質問の下でもFAQに従っていない:解決すべき実際の問題はありません。質問にはコード固有の問題は解決されておらず、本質的に概念的なものです。そして、私がテンプレートhaskellを避けるべきかという質問に基づいて、それスタックオーバーフローに該当しますが、推奨エンジンではありません
エリックフィリップス

27
@ErikPhilips推奨エンジンの側面はこの質問には関係ありません。これは、さまざまなツール間の決定に言及していることに気づくためです(たとえば、「使用する言語を教えてください」)。対照的に、私は特にテンプレートHaskellについての説明を求めているだけであり、FAQには「あなたの動機が「他の人に[空白]を説明してほしい」というのであれば、おそらく大丈夫です」とあります。たとえば、GOTOがまだ有害と見なさ
Dan Burton

29
再開するための投票。質問のレベルが高いからといって、それが良い質問ではないという意味ではありません。
ジェルジAndrasek

回答:


171

テンプレートHaskellを回避する1つの理由は、全体として型セーフではないため、「Haskellの精神」の大部分に反するためです。これのいくつかの例はここにあります:

  • THコードの一部がどのようなHaskell ASTを生成するか、それがどこに現れるかを制御することはできません。typeの値を持つことができますがExp、それがa [Char]またはa を表す式であるかどうかはわかりません(a -> (forall b . b -> c))。関数が特定の型の式のみを生成する、関数の宣言のみを生成する、またはデータコンストラクター一致パターンのみを生成するなどの表現ができる場合、THはより信頼性が高くなります。
  • コンパイルしない式を生成できます。foo存在しない自由変数を参照する式を生成しましたか?幸運なことに、実際にコードジェネレーターを使用しているときに、その特定のコードの生成をトリガーする状況でのみ表示されます。単体テストも非常に難しいです。

THも非常に危険です。

  • コンパイル時に実行されるコードは任意に実行できます IOミサイルの発射やクレジットカードの盗用など、。THエクスプロイトを探すためにダウンロードしたすべてのcabalパッケージを調べる必要はありません。
  • THは「モジュールプライベート」関数と定義にアクセスでき、場合によってはカプセル化を完全に壊します。

次に、TH関数をライブラリ開発者として使用するのが面倒になるいくつかの問題があります。

  • THコードは常に合成可能であるとは限りません。誰かがレンズ用のジェネレータを作成するとします。多くの場合、そのジェネレータは、「エンドユーザー」だけが直接呼び出せるように構成され、他のTHコードからは呼び出せません。たとえば、パラメータとしてレンズを生成する型コンストラクタのリスト。コードでそのリストを生成するのは難しいですが、ユーザーはgenerateLenses [''Foo, ''Bar]
  • 開発者は、THコードを構成できることさえ知りません。あなたが書くことができることを知っていましたforM_ [''Foo, ''Bar] generateLensか?Qは単なるモナドなので、通常の関数をすべて使用できます。これを知らない人もいます。そのため、同じ機能を持つ本質的に同じ機能の複数のオーバーロードバージョンが作成され、これらの機能は特定の膨らみ効果をもたらします。また、ほとんどの人は、Q必要のないときでもジェネレータをモナドで記述しbla :: IO Int; bla = return 3ます。これは、記述のようなものです。あなたは関数に必要以上の「環境」を与えており、関数のクライアントはその効果としてその環境を提供する必要があります。

最後に、TH関数をエンドユーザーとして使用するのが面白くないものがあります。

  • 不透明度。TH機能にタイプがある場合Q Decがある場合、モジュールのトップレベルで絶対に何でも生成でき、生成されるものを完全に制御することはできません。
  • モノリシズム。開発者が許可しない限り、TH関数が生成する量を制御することはできません。データベースインターフェース JSONシリアル化インターフェースを生成する関数を見つけた場合、「いいえ、データベースインターフェースのみが必要です。おかげで、独自のJSONインターフェースをロールバックします」とは言えません。
  • 実行時間。THコードの実行には比較的長い時間がかかります。コードは、ファイルがコンパイルされるたびに新しく解釈され、多くの場合、実行するTHコードにはロードする必要のある大量のパッケージが必要です。これにより、コンパイル時間が大幅に遅くなります。

4
これに加えて、template-haskellは歴史的に十分に文書化されていません。(もう一度見たところ、少なくとも今のところはわずかに良くなっているように見えますが)また、template-haskellを理解するには、ある程度の複雑さを課すHaskell言語の文法を本質的に理解する必要があります(Schemeではありません)。これら2つのことは、私がHaskellの初心者であったときにTHを理解することにわずらわしくないことを意図的にもたらしました。
mightybyte

14
テンプレートHaskellを使用すると、突然、宣言の順序が重要になることを忘れないでください。THは、Haskellの滑らかな磨き(1.4、'98、2010、またはグラスゴーでさえ)を考えると、期待されるほど緊密に統合されていません。
Thomas M. DuBuisson

13
あまり問題なくHaskellを推論できます。テンプレートHaskellについてはそのような保証はありません。
12

15
そして、THのタイプセーフな代替のOlegの約束はどうなりましたか?私は彼の "Finally Tagless、Partially Evaluated"の論文と彼のメモの詳細を基にした彼の作品をここで参照しています。彼らがそれを発表したときそれはとても有望に見えた、そしてそれから私はそれについて別の言葉を聞いたことがない。
Gabriel Gonzalez


53

これは私自身の意見です。

  • 使うのは醜いです。$(fooBar ''Asdf)見栄えがしません。表面的な、確かですが、それは貢献しています。

  • 書くのはもっと醜いです。引用は時々機能しますが、多くの場合、手動でASTのグラフトと配管を行わなければなりません。APIは、あなたが気にまだ発送には必要のないケースの多くが常にあります、大きくて扱いにくい、そしてあなたが世話を行う場合は、およそ、複数の類似しているが同一ではない形態で存在する傾向がある(データ対のnewtype、記録スタイルと通常のコンストラクタなど)。書くのは退屈で繰り返しが多く、機械的ではないほど複雑です。改革案のアドレスこの一部(引用符はより広く適用すること)。

  • ステージ制限は地獄です。同じモジュールで定義された関数をスプライスできないのは、その小さな部分です。別の結果として、トップレベルのスプライスがある場合、モジュール内のそれ以降のすべては、その前の何にもスコープから外れます。このプロパティを持つ他の言語(C、C ++)は、宣言を転送できるようにすることで機能しますが、Haskellはそうではありません。スプライスされた宣言またはそれらの依存関係と依存関係の間で循環参照が必要な場合は、通常、ただ混乱しています。

  • それは無規律です。つまり、抽象化を表現するとき、たいていの場合、その抽象化の背後にある種の原則や概念があるということです。多くの抽象化では、それらの背後にある原則をそのタイプで表現できます。型クラスの場合、インスタンスが従うべき法則を定式化でき、クライアントが引き受けることができます。GHCの新しいジェネリック機能を使用して、任意のデータ型(範囲内)でインスタンス宣言の形式を抽象化すると、「合計型の場合はこのように機能し、製品型の場合はそのように機能します」と言えます。一方、テンプレートHaskellは単なるマクロです。これはアイデアのレベルでの抽象化ではなく、ASTのレベルでの抽象化です。プレーンテキストのレベルでの抽象化よりも優れていますが、適度な程度です。*

  • それはあなたをGHCに結びつけます。理論的には別のコンパイラーがそれを実装することもできますが、実際にはこれが起こることはないと思います。(これは、現時点でGHCによってのみ実装されている可能性があるさまざまな型システム拡張とは対照的ですが、将来、他のコンパイラーによって採用され、最終的に標準化されることは容易に想像できます。)

  • APIは安定していません。新しい言語機能がGHCに追加され、それらをサポートするようにtemplate-haskellパッケージが更新される場合、これには、THデータ型に対する下位互換性のない変更が含まれることがよくあります。THコードをGHCの2つ以上のバージョンと互換性を持たせたい場合は、非常に注意して、おそらく使用する必要がありますCPP

  • 一般的な原則として、ジョブに適切なツールを使用し、それで十分な最小のツールを使用する必要があります。その例では、テンプレートHaskellはこのようなものです。それを行う方法がテンプレートHaskellではない場合、それが一般的に望ましい方法です。

テンプレートHaskellの利点は、他の方法では実行できなかったことが、それを使用して実行できることです。これは大きなものです。ほとんどの場合、THが使用されるものは、コンパイラー機能として直接実装された場合にのみ実行できます。THを使用すると、これらのことを実行でき、潜在的なコンパイラー拡張機能をはるかに軽量で再利用可能な方法でプロトタイプ化できるため(たとえば、さまざまなレンズパッケージを参照)、両方を使用すると非常に有益です。

テンプレート・ハスケルに対して否定的な感情があると思う理由を要約すると、それは多くの問題を解決しますが、それが解決する特定の問題については、その問題を解決するのにより適した、より洗練された、統制のとれたソリューションがあるはずです。ボイラープレートを自動的に生成しても問題を解決しない、ボイラープレートを用意する必要がなくなるもの。

*私はしばしばCPP、それが解決できる問題に対して、より優れた電力対重量比を持っていると感じています。

EDIT 23-04-14:上記で頻繁に取得しようとしていて、つい最近になって初めて、抽象化と重複排除には重要な違いがあるということです。適切な抽象化は副作用として重複排除をもたらすことが多く、重複は抽象化が不十分であることの明確な兆候であることがよくありますが、それが価値がある理由ではありません。適切な抽象化は、コードを正しく、包括的で、保守可能なものにするものです。重複排除はそれを短くするだけです。テンプレートHaskellは、一般的なマクロと同様に、重複排除のためのツールです。


「CPPは、解決できる問題に対して、より優れた電力対重量比を備えています」。確かに。そしてC99では、あなたが望むものは何でも解決できます。以下を考慮してください:COSChaos。私はまた、人々がAST生成の方が優れていると考える理由を理解していません。あいまい性が増し、他の言語機能との直交性が低下します
Britton Kerin、

31

dflemstrが提起するポイントのいくつかを取り上げたいと思います。

THをタイプチェックできないので、そんな心配はありません。どうして?エラーがあったとしても、コンパイル時間になるからです。これが私の主張を強化するかどうかはわかりませんが、これは精神的に、C ++でテンプレートを使用するときに受け取るエラーに似ています。生成されたコードのきれいに印刷されたバージョンが表示されるので、これらのエラーはC ++のエラーよりも理解しやすいと思います。

TH式/準引用符が高度な機能を実行して、トリッキーなコーナーが隠れてしまう可能性がある場合、それはお勧めできません。

私は最近取り組んでいる準クォータ(haskell-src-exts / metaを使用)でこのルールをかなり破っています-https ://github.com/mgsloan/quasi-extras/tree/master/examples。これは、一般化されたリスト内包表記でスプライスできないなどのいくつかのバグを引き起こすことを知っています。ただし、http://hackage.haskell.org/trac/ghc/blog/Template%20Haskell%20Proposalのアイデアのいくつかは、可能性が高いと思いますコンパイラーされる。それまでは、HaskellをTHツリーに解析するためのライブラリは、ほぼ完全な近似です。

コンパイル速度/依存関係については、「ゼロ」パッケージを使用して、生成されたコードをインライン化できます。これは少なくとも特定のライブラリのユーザーにとっては便利ですが、ライブラリを編集する場合には、これ以上のことはできません。THの依存関係は、生成されたバイナリを膨張させることができますか?コンパイルされたコードで参照されていないものはすべて除外したと思いました。

Haskellモジュールのステージングの制限/コンパイル手順の分割には問題があります。

RE不透明度:これは、呼び出すすべてのライブラリー関数と同じです。Data.List.groupByが何を行うかを制御することはできません。バージョン番号が互換性について何かを教えてくれるという合理的な「保証」/規則があります。変更の際は多少異なる場合がございます。

これは、zerothを使用することで成果が得られる場所です。つまり、既に生成されたファイルのバージョン管理を行っているため、生成されたコードの形式がいつ変更されたかが常にわかります。ただし、生成されたコードが大量にある場合は、差分を見るのは少しぎこちないかもしれません。そのため、より良い開発者インターフェースが便利な場所の1つです。

REモノリシズム:独自のコンパイル時コードを使用して、TH式の結果を後処理することができます。トップレベルの宣言タイプ/名前でフィルタリングするコードはそれほど多くありません。一体、これを一般的に行う関数を書くことを想像できます。準クォーターを変更/モノリシック化しない場合、「QuasiQuoter」でパターンマッチングを行い、使用されている変換を抽出するか、古い変換を新しい変換にすることができます。


1
不透明度/モノリシズムについてもちろん、a [Dec]をウォークスルーして不要なものを削除できますが、関数がJSONインターフェースを生成するときに外部定義ファイルを読み取るとします。これを使用Decしないからといって、ジェネレーターが定義ファイルの検索を停止せず、コンパイルが失敗します。そのため、Q新しい名前(など)を生成できるがIO、を許可しないモナドのより制限されたバージョンを用意すると、結果をフィルター処理したり、他の構成を実行したりできるようになります。 。
dflemstr

1
私は同意します、Q /見積もりの​​非IOバージョンがあるはずです!これは解決にも役立ちます-stackoverflow.com/questions/7107308/…。コンパイル時のコードが安全でないことを何も実行していないことを確認したら、結果のコードで安全チェッカーを実行し、プライベートなものを参照しないようにすることができます。
mgsloan

1
反論を書いたことがありますか?あなたの約束されたリンクをまだ待っています。この回答の古いコンテンツを探している方:stackoverflow.com/revisions/10859441/1、および削除されたコンテンツを閲覧できる方:stackoverflow.com/revisions/10913718/6
Dan Burton

1
ハッキングのバージョンよりも新しいバージョンのゼロスはありますか?その1つ(およびdarcsリポジトリ)は2009年に最後に更新されました。どちらのコピーも現在のghc(7.6)ではビルドされません。
aavogt 2013年

1
@aavogt tgeekyは、それを固定に取り組んでいたが、私は彼が終了したとは思わない:github.com/technogeeky/zeroth 誰もがこのために/メイク何かそれをしないならば、私は最終的に周りに取得します。
mgsloan 2013年

16

この答えは、illissiusによってポイントごとに持ち上がった問題への応答です。

  • 使うのは醜いです。$(fooBar '' Asdf)は見栄えがしません。表面的な、確かですが、それは貢献しています。

同意する。$()は、言語の一部のように見えるように選択されたように感じます-Haskellの使い慣れたシンボルパレットを使用しています。しかし、それはまさにあなたがマクロスプライシングに使用されるシンボルにあなたが望まない/望まないことです。それらは間違いなく配合量が多すぎますが、この化粧品の側面は非常に重要です。{{}}の外観は、スプライスが非常に視覚的に区別できるため、気に入っています。

  • 書くのはもっと醜いです。引用は時々機能しますが、多くの場合、手動でASTのグラフトと配管を行わなければなりません。[API] [1]は大きく扱いにくいため、気にしなくてもディスパッチする必要があるケースは常に多くあります。気になるケースは、似ているが同一ではない形式で複数存在する傾向があります(データvs. newtype、record-style vs.通常のコンストラクターなど)。書くのは退屈で繰り返しが多く、機械的ではないほど複雑です。[改革案] [2]はこれの一部に対処します(引用をより広く適用できるようにします)。

私もこれに同意しますが、「THの新しい方向性」のコメントの一部に見られるように、すぐに使えるAST引用の欠如は重大な欠陥ではありません。このWIPパッケージでは、これらの問題にライブラリ形式で対処しようとしています。https//github.com/mgsloan/quasi-extras。これまでのところ、スプライシングを通常より数カ所多く許可しており、ASTでパターンマッチングを行うことができます。

  • ステージ制限は地獄です。同じモジュールで定義された関数をスプライスできないのは、その小さな部分です。別の結果として、トップレベルのスプライスがある場合、モジュール内のそれ以降のすべては、その前の何にもスコープから外れます。このプロパティを持つ他の言語(C、C ++)は、宣言を転送できるようにすることで機能しますが、Haskellはそうではありません。スプライスされた宣言またはそれらの依存関係と依存関係の間で循環参照が必要な場合は、通常、ただ混乱しています。

私は以前に不可能であった循環TH定義の問題に遭遇しました...それは非常に迷惑です。解決策はありますが、それは醜いです-生成されたすべての宣言を組み合わせるTH式で循環依存関係に関係するものをラップしてください。これらの宣言ジェネレーターの1つは、Haskellコードを受け入れる準クォーターにすぎません。

  • それは無理です。つまり、抽象化を表現する場合、ほとんどの場合、その抽象化の背後にはある種の原則や概念があります。多くの抽象化では、それらの背後にある原則をそのタイプで表現できます。タイプクラスを定義すると、多くの場合、インスタンスが従うべき法則を定式化し、クライアントが引き受けることができます。GHCの[新しいジェネリック機能] [3]を使用して、任意のデータ型(境界内)でインスタンス宣言の形式を抽象化すると、「合計型の場合、このように機能し、製品型の場合、そのように機能します。 」しかし、テンプレートHaskellは単なるばかげたマクロです。それはアイデアのレベルでの抽象化ではなく、ASTのレベルでの抽象化です。プレーンテキストのレベルでの抽象化よりも優れていますが、適度です。

あなたがそれで無茶なことをするなら、それは無茶です。唯一の違いは、コンパイラーが実装した抽象化のメカニズムにより、抽象化に漏れがないという確信が高まることです。おそらく、言語デザインを民主化することは少し恐ろしいように聞こえます!THライブラリの作成者は、提供するツールの意味と結果を明確かつ明確に文書化する必要があります。原則的なTHの良い例は、派生パッケージです。http//hackage.haskell.org/package/derive-派生の多くの例が実際の派生を/ specify /するようにDSLを使用します。

  • それはあなたをGHCに結びつけます。理論的には別のコンパイラーがそれを実装することもできますが、実際にはこれが起こることはないと思います。(これは、現時点でGHCによってのみ実装されている可能性があるさまざまな型システム拡張とは対照的ですが、将来、他のコンパイラーによって採用され、最終的に標準化されることは容易に想像できます。)

それはかなり良い点です-TH APIはかなり大きくて不格好です。再実装するのは難しいかもしれません。ただし、Haskell ASTを表す問題を切り分ける方法はほんのわずかです。TH ADTをコピーし、内部AST表現にコンバーターを作成すると、そこにかなりの道が得られると思います。これは、haskell-src-metaを作成する(重要ではない)作業と同等です。また、TH ASTをきれいに出力し、コンパイラーの内部パーサーを使用することで、単純に再実装することもできます。

私は間違っているかもしれませんが、実装の観点からは、THがコンパイラー拡張の複雑なものであるとは思いません。これは実際には「シンプルに保つ」ことの利点の1つであり、基本的なレイヤーが理論的に魅力的な、静的に検証可能なテンプレートシステムにならないことです。

  • APIは安定していません。新しい言語機能がGHCに追加され、それらをサポートするようにtemplate-haskellパッケージが更新される場合、これには、THデータ型に対する下位互換性のない変更が含まれることがよくあります。THコードをGHCの2つ以上のバージョンと互換性を持たせたい場合は、非常に注意して、おそらく使用する必要がありますCPP

これも良い点ですが、やや劇的です。最近、APIの追加が行われていますが、破損を引き起こすような広範囲な変更は行われていません。また、前述の優れたASTクォーティングを使用すると、実際に使用する必要があるAPIを大幅に削減できると思います。構築/照合で別個の関数が必要なく、代わりにリテラルとして表現されている場合、ほとんどのAPIは表示されなくなります。さらに、作成したコードは、Haskellに類似した言語のAST表現に移植しやすくなります。


要約すると、THは強力な、半無視されたツールだと思います。嫌悪感が減れば、ライブラリのより活発なエコシステムにつながり、より多くの言語機能プロトタイプの実装を促進できます。THは強力なツールであり、ほとんどすべてのことを/ do /させることができることが観察されています。無政府状態!まあ、それは、このパワーを使用すると、その制限のほとんどを克服でき、非常に原理的なメタプログラミングアプローチが可能なシステムを構築できると私は考えています。このように「適切な」実装の設計が徐々に明らかになるため、「適切な」実装をシミュレートするために醜いハックを使用する価値はあります。

私の個人的な理想のバージョンのニルヴァーナでは、言語の多くは実際にはコンパイラーからこれらのさまざまなライブラリーに移動します。ライブラリとして機能が実装されているという事実は、忠実に抽象化する機能に大きな影響を与えません。

ボイラープレートコードに対する典型的なHaskellの答えは何ですか?抽象化。私たちのお気に入りの抽象化は何ですか?関数と型クラス!

型クラスを使用すると、一連のメソッドを定義できます。これにより、そのクラスで汎用的なすべての関数で使用できます。ただし、これ以外に、クラスがボイラープレートを回避する唯一の方法は、「デフォルトの定義」を提供することです。さて、ここに非公認機能の例があります!

  • 最小のバインディングセットは宣言できません/コンパイラーでチェックできません。これは、相互の再帰により、不注意な定義に終わりをもたらす可能性があります。

  • これによりもたらされる優れた利便性とパワーにもかかわらず、孤立したインスタンスがあるため、スーパークラスのデフォルトを指定できませんhttp://lukepalmer.wordpress.com/2009/01/25/a-world-without-orphans/ これらにより 、数値階層を優雅に!

  • メソッドのデフォルトのTHのような機能を追求すると、http: //www.haskell.org/haskellwiki/GHC.Genericsにつながりました。これはクールなものですが、これらのジェネリックを使用してコードをデバッグする唯一の経験は、ASTと同じくらい複雑なADTに誘導される型のサイズのため、ほとんど不可能でした。https://github.com/mgsloan/th-extra/commit/d7784d95d396eb3abdb409a24360beb03731c88c

    言い換えると、これはTHによって提供される機能を追い求めましたが、言語の全ドメインである構成言語を型システム表現に引き上げる必要がありました。私はそれがあなたの一般的な問題にうまく機能しているのを見ることができますが、複雑な問題では、THハッカーよりもはるかに恐ろしいシンボルの山を生み出す傾向があるようです。

    THは出力コードの値レベルのコンパイル時計算を提供しますが、ジェネリクスはコードのパターンマッチング/再帰部分を型システムに持ち上げるように強制します。これはユーザーをいくつかのかなり便利な方法で制限しますが、複雑さはそれだけの価値はないと思います。

THの拒否とlispのようなメタプログラミングは、インスタンスの宣言のようなより柔軟なマクロ展開の代わりに、method-defaultsのようなものへの選好につながったと思います。予期しない結果につながる可能性のあるものを回避する規律は賢明ですが、Haskellの有能な型システムが他の多くの環境よりも信頼できるメタプログラミングを可能にすることを無視してはなりません(生成されたコードをチェックすることにより)。


4
この答えは、それだけではうまくいきません。あなたが私があなたの答えを適切に読む前に、私が行かなければならない別の答えをたくさん参照しています。
ベンミルウッド

それは本当です。私はそれにもかかわらず話されていることを明確にしようとしました。おそらく私はillisuisのポイントをインラインに編集します。
mgsloan

多分、「無原則」は私が使うべきだったよりも強い言葉であり、私が意図していなかったいくつかの意味合いを含んでいます-それは確かに悪質ではありません!頭の中でこのような感覚や形のない考えがあり、言葉にするのが難しいので、その箇条書きが一番問題でした。「無理」とは、近くのどこかで掴んだ言葉の1つでした。「統制」はおそらく近いです。明確で簡潔な処方がないので、代わりにいくつかの例を挙げました。誰かが私がおそらく何を意味しているかをより明確に説明できれば、私はそれを感謝します!
glaebhoerl

(また、ステージングの制限と醜い書き込みの見積もりを切り替えた可能性もあります。)
glaebhoerl

1
どー!ご指摘いただきありがとうございます。修繕。はい、無規律はおそらくそれを置くより良い方法でしょう。ここでの違いは、実際には「組み込み」、つまり「よく理解された」抽象化メカニズムと、「アドホック」またはユーザー定義の抽象化メカニズムとの違いだと思います。タイプクラスディスパッチと非常によく似たものを実装したTHライブラリを定義できると思います(実行時ではなくコンパイル時ですが)
mgsloan

8

テンプレートHaskellのかなり実用的な問題の1つは、GHCのバイトコードインタープリターが利用可能な場合にのみ機能することです。これは、すべてのアーキテクチャに当てはまるわけではありません。したがって、プログラムがテンプレートHaskellを使用するか、それを使用するライブラリに依存している場合、ARM、MIPS、S390、またはPowerPC CPUが搭載されたマシンでは実行できません。

これは実際に関連しています:git-annexはHaskellで書かれたツールで、ストレージを心配するマシンで実行するのに意味があります。個人的には、NSLU 2で git-annexを実行しています(32 MBのRAM、266 MHzの CPU、Haskellがそのようなハードウェアで正常に動作することをご存知でしたか?)テンプレートHaskellを使用する場合、これは不可能です。

(ARMでのGHCに関する状況は最近大幅に改善されており、7.4.2でも機能すると思いますが、ポイントはまだ残っています)。


1
「テンプレートHaskellは、GHCの組み込みバイトコードコンパイラとインタープリタを使用してスプライス式を実行します。」- haskell.org/ghc/docs/7.6.2/html/users_guide/...
ヨアヒム・ブライトナー

2
ああ、そうですね-いいえ、THはバイトコードインタープリターなしでは機能しませんが、それはghciとは(関連がありますが)異なります。ghciがバイトコードインタープリターに依存していることを考えると、ghciの利用可能性とバイトコードインタープリターの利用可能性の間に完全な関係があったとしても驚かないでしょうが、問題は、ghciの不足ではなく、バイトコードインタープリターの不足です。具体的に。
muhmuhten 2013

1
(ちなみに、ghciはTHのインタラクティブな使用に対するサポートが非常に貧弱です。試してみてくださいghci -XTemplateHaskell <<< '$(do Language.Haskell.TH.runIO $ (System.Random.randomIO :: IO Int) >>= print; [| 1 |] )'
muhmuhten 2013

さて、ghciについて、コードがghciバイナリで対話的に送られるのか、THスプライスから送られるのかに関係なく、GHCが(コンパイルの代わりに)コードを解釈する能力について言及していました。
Joachim Breitner 2013

6

なぜTHは悪いのですか?私にとっては、これに帰着します:

THを使用して自動生成しようとしているほど多くの反復的なコードを生成する必要がある場合、それは間違っています。

それについて考えてください。Haskellの魅力の半分は、その高レベルの設計により、他の言語で書かなければならない無駄な大量のボイラープレートコードを回避できることです。コンパイル時のコード生成が必要な場合、基本的には、言語またはアプリケーションの設計のいずれかが失敗したことを示しています。そして私たちのプログラマーは失敗するのを好まない。

もちろん、それが必要な場合もあります。しかし、デザインを少し賢くすることでTHの必要性を回避できる場合もあります。

(もう1つは、THが非常に低レベルであることです。壮大な高レベルのデザインはありません。GHCの内部実装の詳細の多くが公開されています。これにより、APIが変更されやすくなります...)


特に私たちがQuasiQuotesを考慮した場合、それはあなたの言語またはアプリケーションがあなたに失敗したことを意味するとは思いません。構文に関しては常にトレードオフがあります。一部の構文は特定のドメインをより適切に説明しているため、別の構文に切り替えられるようにしたい場合があります。QuasiQuotesを使用すると、構文をエレガントに切り替えることができます。これは非常に強力であり、Yesodや他のアプリで使用されます。HTMLのような構文を使用してHTML生成コードを記述できることは、すばらしい機能です。
CoolCodeBro

@CoolCodeBroええ、準引用はとてもいいですし、THに少し直交していると思います。(明らかに、THの上に実装されています。)THを使用してクラスインスタンスを生成したり、複数のアリティの関数を作成したりすることなどについて、もっと考えていました。
MathematicalOrchid
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.