2

evalExpression :: Exp -> Valueモジュール内にA、引数に対するパターン マッチングに大きく依存する関数がありますExp

ファイルが大きくなり、さらに整理する必要があります。Aモジュールを modules A.GHC.NumA.GHC.Typesなどに分割したいと思います。

  • GHCでモジュールを別のモジュール内にインライン化する方法はありますか? これを実行しようとしましたが、「モジュールのインポートがサイクルを形成しています」というエラーが表示されます

また

  • 同じモジュールを 2 つの異なるファイルに書き込む方法はありますか?

また

  • A.evalExp(try と catch の意味で) の値を返そうとする関数を定義できますか?A.GHC.Num.evalExpエラー (非網羅的なパターン マッチ) をキャッシュすると、 を返そうと A.GHC.Types.evalExpします。

更新

循環依存関係を解決しようとしましたが、GHC は納得できませんでした。「あいまいな発生」と表示されます。

4

1 に答える 1

5

いいえ、モジュールを複数のファイルに分割することはできません。また、異なる場所で関数を定義することもできません。これに最も近いのは、さまざまなモジュールで定義されたインスタンスを持つ型クラスの一部である関数です。しかし、それはおそらくあなたがここで望んでいるものではありません.

ただし、相互に再帰的なモジュールをコンパイルすることは可能です。理論的には、これは Just Work (tm) のはずですが、GHC ではそれを行うためにちょっとしたフープ ジャンプが必要です。詳細については、ユーザーズ ガイドを参照してください。周期的なモジュールのインポート エラーが発生した場合、これによりそのバージョンが機能するようになります。

網羅的なパターン マッチ エラーをキャッチして、別のことを試す "良い" 方法はありません。あまり良くない方法が複数ありますが、おそらくそこに行きたくないでしょう。

多数のケースを含む 1 つのデータ型でパターン マッチングを行うことが目標である場合、相互に再帰的なモジュールや型クラスを台無しにすることなく物事を分割する最も簡単な方法は、各コンストラクターの内容を取得する別のモジュールに別の関数を持たせることです。直接引数として、他のものをインポートしてディスパッチを行うモジュール内のすべてのケースで単一のパターンマッチ。

同様の名前のモジュールを持つ、FooケースA、、、 &c.を持つタイプがあるとします。B「中央」モジュールでは、次のものを使用できます。

doStuff (A x y) = A.doStuffA x y
doStuff (B z) = B.doStuffB z

...等々。

一部のシナリオでは、同様の方法でデータ型全体を分割し、コンストラクターごとに個別の型を作成することも理にかなっていますdata Foo = A FooA | B FooB | ...。これは、複数の方法で相互に再帰的になるデータ型が複雑に絡み合っている場合に最も役立ちます。典型的な例は AST です。


さて、大ざっぱなことをせずに、必要なものをシミュレートする 1 つの方法を次に示します。

まず、理想的な方法で関数をさまざまなモジュールに分割します。次に、次の変更を行います。

  • 結果の型を useMaybeに変更し、結果をラップしJustて、生成されるすべてをキャッチする既定のケースを追加しますNothing

  • 追加の引数を追加し、再帰呼び出しをにr置き換えます。evalExpr

evalExp中央のモジュールから、ケースを含む各モジュールをインポートします。あいまいさを避けるために、必要に応じて修飾されたインポートを使用してください。各 eval 関数のリストを定義し (それらはすべて同じ型である必要があります)、「実数」evalExpを次のように定義します。

expCases = [A.GHC.Num.evalExp, A.GHC.Types.evalExpr {- etc... -} ]

evalExpCases exp = mapMaybe (\eval -> eval evalExp exp) expCases

evalExp exp = case evalExpCases exp of
                  (r:_) -> -- use the first result 
                  [] -> -- no cases matched

基本的に、これは、Maybe網羅的でないパターンを明示的に示すために使用し、直接再帰をfix、結合された再帰関数が (個別に非再帰的な) ケースの各セットに渡されるスタイルの構造に置き換えます。

かなり厄介ですが、本当に良い方法があるかどうかはわかりません。Template Haskell を使用してすべてのがらくたを自動化する方法があるかもしれませんが、それはおそらく手動で行うのと同じくらい面倒です。

個人的には、おそらく歯を食いしばって、すべてを 1 つのモジュールに残すでしょう。

于 2013-02-14T16:02:08.513 に答える