f#中的循环类型引用

rkr*_*ahl 4 .net generics f#

我正在为F#中的linq表达式构建器编写简单的excel公式.我正在使用递归表达式构建器将公式解析为AST并构建表达式.我一直坚持将环境((字符串,表达式)映射对)传递给该调用中生成的表达式:

Expression.Lambda<System.Func<double>>(eval pexpr).Compile()
Run Code Online (Sandbox Code Playgroud)

解析pexpr的位置AST和eval是表达式构建函数.

问题是定义类型应该如下所示:

type ExprFunc = Func<ExprFunc map, double>
Expression.Lambda<ExprFunc>(eval pexpr).Compile()
Run Code Online (Sandbox Code Playgroud)

如果pexpr包含对Var("name")形式的其他表达式的引用,我想注入在环境映射中使用"name"搜索函数的表达式并调用它,在该调用中传递相同的环境映射.

不幸的是,编译器说不:

此类型定义涉及通过缩写的立即循环引用

有没有办法在.net中定义这样的函数类型?

Tom*_*cek 9

如果要编写引用自身的类型声明,则不能使用F#类型别名.问题是F#类型别名在编译时被擦除,因此递归引用将导致无限类型:

Func<Func<Func<Func<... map, double> map, double> map, double> map, double>
Run Code Online (Sandbox Code Playgroud)

在F#中,最简单的替代方法可能是定义一个简单的区分联合:

type ExprFunc = EF of Func<ExprFunc map, double> 
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用该模式EF f在F#函数中获取基础委托.直接这样做不会起作用Expression.Lambda,所以你可能需要这样的东西:

type ExprFunc = Func<ExprFunc map, double> 
and WrappedExprFunc = EF of ExprFunc
Run Code Online (Sandbox Code Playgroud)

在调用时Expression.Lambda,您需要使用Func<..>委托作为参数,但是您需要修改代码eval以正确处理包装的参数(这将是类型WrappedExprFunc):

Expression.Lambda<ExprFunc>(eval pexpr).Compile()   
Run Code Online (Sandbox Code Playgroud)

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