我对执行以下操作的最佳方法有疑问
我有一个 B 类,我在 B 上有一个组合器, 让 foo : B -> int。
我希望类 B 将组合器封装为方法,因此我添加了类型扩展。
后来我意识到 foo 相当昂贵,并且想通过延迟评估来缓存它的结果
因此,我通过将组合器作为函数传递给构造函数,然后在构造函数中使用 foo = lazy(foo self) 初始化字段,为系统添加了一个巨大的离合器。
即
type foo =
class
val x : int Lazy
new (comb) as self = {x=lazy(comb self);}
end
let something (x:foo) = 1
type foo with
new() = foo(something)
这显然感觉不对
我看到的解决这个问题的两个选项是1,创建一个接口(interface)并让foo继承该接口(interface),2,将所有内容都设为静态方法,然后从这些静态方法中创建组合器(与将它们附加到类相反) ...)
这两个都没有太大吸引力,我想知道我是否错过了选项 3
哦,我还无法得到 let rec 并能很好地处理这个问题,我也不想这样做,因为上面语句中的“某些东西”取决于一个函数,而这个函数又依赖于一个函数,而这个函数又依赖于一个函数。一个函数(3 深)。
如有任何建议,我们将不胜感激
最佳答案
我认为您当前的设计没有任何问题。关键点是,如果您在同一文件(和同一模块)中定义类型 Foo
以及该类型的扩展,那么 F# 会将定义的两部分合并为一个.NET 类型。因此,它被定义为两个单独的部分这一事实只是一个实现细节。
如果您不想公开采用组合器的构造函数,可以将其标记为private
。加上一些额外的更改(即使用隐式构造函数语法),代码片段将如下所示:
type Foo private (comb) as self =
let x : Lazy<int> = lazy comb self
let something (x:Foo) = 1
type Foo with
new() = Foo(something)
如果您想将某些东西保留为单独的函数,那么这是一个很好的解决方案。 F# PowerPack 中的许多数字类型都遵循此模式(例如,参见 definition of complex numbers )
关于f# - F# 中的循环函数/类型依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5559699/