Implementing the Haskell-MaybeMonad in F# - how can we get this lazy?

坚强是说给别人听的谎言 提交于 2019-12-03 09:07:33

You can implement additional methods Run/Combine in MaybeBuilder so result shall be the following:

let bindM x k =
match x with
| Some value -> k value
| None   -> None

let returnM x = Some x

type MaybeBuilder() =
    member this.Bind(x, k) = bindM x k
    member this.Return(x)  = returnM x
    member this.ReturnFrom(x) = x
    member this.Delay(f)   = f
    member this.Combine(a, b) = if Option.isSome a then a else b()
    member this.Run(f) = f()

let maybe = MaybeBuilder()

//Sample dictionaries (the same with original sample)
let fullNamesDb = ... 
let nickNamesDb = ...
let prefsDb = ....

let lookUp name = 
    let findName m = maybe {
        let! v = Map.tryFind name m
        return! prefsDb.TryFind v 
        }

    maybe {
        return! findName fullNamesDb
        return! findName nickNamesDb 
    }


let billGatesPref = lookUp "Bill Gates" |> printfn "%A" // Some "HTML"
let billyPref = lookUp "billy" |> printfn "%A" // Some "HTML"
let billClintonPref = lookUp "Bill Clinton" |> printfn "%A" // Some "Plain"
let steffenPref = lookUp "Steffen" |> printfn "%A" // None
let noPref = lookUp "No Pref Guy" |> printfn "%A" // None

There's always Lazy, which is effectively what you have here but with different syntax:

let mplus m1 (m2 : Lazy<'a option>) =
    match m1 with
    | Some _ as m -> m
    | None -> m2.Force()

let (+) = mplus

let lookUp name = maybe {
    let! combined = fullNamesDb.TryFind name + lazy (nickNamesDb.TryFind name)
    return! prefsDb.TryFind combined
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!