5

F#でlinq式ビルダーに簡単なExcel式を書いています。数式をASTに解析し、再帰式ビルダーを使用して式を作成しています。私はその呼び出しで生成された式に環境((文字列、式)ペアのマップ)を渡すことに固執しました:

Expression.Lambda<System.Func<double>>(eval pexpr).Compile()

ここで、pexprはASTで解析され、evalは式ビルダー関数です。

問題は、次のように見えるタイプを定義することです。

type ExprFunc = Func<ExprFunc map, double>
Expression.Lambda<ExprFunc>(eval pexpr).Compile()

pexprにVar( "name")の形式で他の式への参照が含まれている場合、環境マップで "name"を使用して関数を検索する式を挿入して呼び出し、同じ環境マップをその呼び出しで渡します。

残念ながら、コンパイラはノーと言っています。

この型の定義には、省略形による即時の循環参照が含まれます

.netでそのような関数型を定義する方法はありますか?

4

1 に答える 1

10

自分自身を参照する型宣言を記述したい場合、F# 型エイリアスは使用できません。問題は、F# 型エイリアスがコンパイル時に消去されるため、再帰参照によって無限型になることです。

Func<Func<Func<Func<... map, double> map, double> map, double> map, double>

F# では、おそらく最も簡単な方法は、単純な判別共用体を定義することです。

type ExprFunc = EF of Func<ExprFunc map, double> 

次に、パターンを使用してEF f、F# 関数で基になるデリゲートを取得できます。ただし、これを直接実行しても機能しExpression.Lambdaないため、次のようなものが必要になるでしょう。

type ExprFunc = Func<ExprFunc map, double> 
and WrappedExprFunc = EF of ExprFunc

を呼び出すときは、デリゲートを引数としてExpression.Lambda使用する必要がありますが、ラップされた引数 (タイプは)を適切に処理するには、コードを変更する必要があります。Func<..>evalWrappedExprFunc

Expression.Lambda<ExprFunc>(eval pexpr).Compile()   

余談ですが、C# 式ツリーを生成している場合はWrappedExprFunc、クラスとして定義する方が処理しやすいため、簡単に定義できます。それはあなたのコードの残りの部分に依存します。

于 2012-09-07T13:22:11.423 に答える