2

我有一个关于以下最佳方式的问题

我有一个 B 类,我在 B 上有一个组合器,让 foo : B -> int。

我希望 B 类将组合器封装为方法,因此我将其添加为类型扩展。

然后我后来意识到 foo 非常昂贵,并且想通过惰性评估来缓存它的结果

因此,我通过将组合器作为函数传递给构造函数,然后在构造函数中使用 foo = lazy(foo self) 初始化一个字段,从而为系统添加了一个巨大的离合器。

IE

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,创建一个接口并让 foo 继承该接口,2,使所有内容成为静态方法,然后从这些静态方法中创建组合器(与将它们附加到类相反... )

这些都不是很吸引人,我想知道我是否错过了选项 3

哦,我还不能让 let rec 和它一起工作,我也不想因为上面语句中的“某事”依赖于一个依赖于一个函数的函数,这个函数依赖于一个函数( 3深)。

任何意见,将不胜感激

4

2 回答 2

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)

如果您想保留something为单独的功能,那么这是一个很好的解决方案。F# PowerPack 中的许多数字类型都遵循此模式(例如,请参阅复数定义

于 2011-04-05T23:39:37.353 回答
2

我不太明白你在追求什么,但我认为这可能会有所帮助:

type foo(comb) as self =
    let x = lazy(comb self)
    static member something (x:foo) = 1 
    new() = foo(foo.something)

一个类型可以用它自己的静态成员递归,所以这是编写代码的一种更简单的方法。

于 2011-04-05T23:39:34.017 回答