我们正试图在F#中构建来自http://www.haskell.org/all_about_monads/html/maybemonad.html的Haskell-MaybeMonad示例。在F#中实现Haskell-MaybeMonad - 我们该如何获得这个懒惰?
这个想法是在两本字典中搜索一个mailaddress。如果其中一个查找返回结果,我们将查看第三个。
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()
let maybe = MaybeBuilder()
//Sample dictionaries
let fullNamesDb =
[("Bill Gates", "[email protected]")
("Bill Clinton", "[email protected]")
("Michael Jackson", "[email protected]")
("No Pref Guy", "[email protected]")]
|> Map.ofList
let nickNamesDb =
[("billy", "[email protected]")
("slick willy", "[email protected]")
("jacko", "[email protected]") ]
|> Map.ofList
let prefsDb =
[("[email protected]", "HTML")
("[email protected]", "Plain")
("[email protected]", "HTML")]
|> Map.ofList
let mplus m1 m2 = if m1 <> None then m1 else m2
let (+) = mplus
let lookUp name = maybe {
let! combined = fullNamesDb.TryFind name + nickNamesDb.TryFind name
return! prefsDb.TryFind combined
}
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
System.Console.ReadKey() |> ignore
问题是我们执行第二次查找,即使第一次查找返回结果。 Haskell的好处在于它评估懒惰。现在我们在F#中寻找类似的东西。我们试过以下,但它看起来丑陋,似乎打破在构建器封装也许逻辑的想法:
let mplus m1 m2 = if m1 <> None then m1 else m2()
let (+) = mplus
let lookUp name = maybe {
let! combined = fullNamesDb.TryFind name + fun _ -> nickNamesDb.TryFind name
return! prefsDb.TryFind combined
}
有没有更好的解决办法?
问候, forki
真棒的想法。太精彩了。 – forki23 2010-07-01 12:21:42