Кто-нибудь построил ленивую монаду в F #? - PullRequest
4 голосов
/ 08 января 2012

Я читал Чисто функциональные структуры данных Криса Окасаки , и мне интересно, есть ли хороший способ построить ленивые алгоритмы с F # внутри монады, которые позволяют ленивые вычисления (ленивая монада).Крис использовал собственное расширение для синтаксиса приостановки / форсирования в SML, но я хотел бы думать, что вместо этого мы могли бы просто использовать простую монаду в F #.Ручное использование lazy и force в F # кажется довольно беспорядочным.

Я нашел эту реализацию в Схеме, но я не знаю, насколько это применимо.

Отмои беглые знания и исследования, это кажется возможным и желательным в разумных пределах.

Пожалуйста, дайте мне знать:)

Ответы [ 2 ]

7 голосов
/ 08 января 2012

Для переноса кода Окасаки, почему бы просто не использовать ключевое слово F # lazy и некоторый вспомогательный синтаксис для экспресс-форсирования, например:

let (!) (x: Lazy<'T>) : 'T = x.Value

Поскольку система типов F # не может должным образом выражать монады, я полагаю, вы предлагаете определить выражение вычисления для отложенных вычислений. Я думаю, что это можно сделать, но как это поможет?

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 голос
/ 22 ноября 2012

Я не уверен, что это поможет, но вы можете вообще избежать использования ключевого слова 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

(отсутствует часть, где Force оценивает его только один раз)).

Поздно, но подумал, что стоит предложить.

...