f#中的循环类型引用

时间:2012-09-07 12:24:24

标签: .net generics f#

我正在为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中定义这样的函数类型?

1 个答案:

答案 0 :(得分:8)

如果要编写引用自身的类型声明,则不能使用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<..>委托作为参数,但是您需要修改eval中的代码以正确处理包装的参数(将是WrappedExprFunc)类型:

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

顺便说一句,如果您正在生成C#表达式树,那么将WrappedExprFunc定义为类可能更容易,因为这样更容易处理。这取决于你的其余代码。