我一直在阅读Chris Okasaki的Purely Functional Data Structures,我想知道是否有一种很好的方法可以在一个启用延迟计算的monad中使用F#构建惰性算法(一个懒惰的monad)。 Chris在SML中使用了自定义扩展来实现暂停/强制语法,但我想我们可以在F#中使用一个简单的monad。在F#中手动使用lazy和force似乎很混乱。
我在Scheme中找到this实现,但我不知道它的适用性。
从我粗略的知识和研究中,在合理的限制范围内似乎既可行又可取。
请让我知道:)。
答案 0 :(得分:7)
要移植Okasaki代码,为什么不使用F#lazy
关键字和一些帮助语法来表示强制,例如:
let (!) (x: Lazy<'T>) : 'T = x.Value
由于F#类型系统无法正确表达monad,我假设您建议为延迟计算定义计算表达式。我想人们可以做到这一点,但这对那有什么帮助呢?
type LazyBuilder =
| Lazy
member this.Return(x: 'T) : Lazy<'T> =
Lazy.CreateFromValue(x)
member this.Bind(x: Lazy<'T1>, f: 'T1 -> Lazy<'T2>) : Lazy<'T2> =
lazy (f x.Value).Value
let test () =
let v =
Lazy {
let! x = lazy 1
let! y = lazy 2
return x + y
}
v.Value
let (!) (x: Lazy<'T>) : 'T = x.Value
let test2 () =
let v =
lazy
let x = lazy 1
let y = lazy 2
!x + !y
!v
答案 1 :(得分:1)
我不确定这会有什么帮助,但如果您出于某种原因特别想要,则可以完全避免使用lazy
关键字:
type ('a, 'b) lazyT = Lz of 'a * ('a -> 'b)
let force (Lz (a, e)) = e a
let pack x = Lz(x, (fun i -> i))
type MyLazyBuilder =
| Mylazy
member this.Bind(x, f) =
match x with
| Lz(xa, xe) ->
Lz(xa, fun x -> force (f (xe x)))
member this.Return(x) = pack x
let sth =
Mylazy {
let! x = pack 12
let! y = pack (x + 1)
return y * x
}
let res = force sth
(没有强制仅评估一次的部分)。
迟到了,但认为值得建议。