有没有人在F#中构建一个懒惰的Monad?

时间:2012-01-07 20:48:22

标签: f# monads lazy-evaluation

我一直在阅读Chris Okasaki的Purely Functional Data Structures,我想知道是否有一种很好的方法可以在一个启用延迟计算的monad中使用F#构建惰性算法(一个懒惰的monad)。 Chris在SML中使用了自定义扩展来实现暂停/强制语法,但我想我们可以在F#中使用一个简单的monad。在F#中手动使用lazy和force似乎很混乱。

我在Scheme中找到this实现,但我不知道它的适用性。

从我粗略的知识和研究中,在合理的限制范围内似乎既可行又可取。

请让我知道:)。

2 个答案:

答案 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

(没有强制仅评估一次的部分)。

迟到了,但认为值得建议。