gpt4 book ai didi

haskell - 在 F# 中实现 Haskell-MaybeMonad - 我们如何才能变得懒惰?

转载 作者:行者123 更新时间:2023-12-04 17:41:25 27 4
gpt4 key购买 nike

我们正在尝试从 http://www.haskell.org/all_about_monads/html/maybemonad.html 构建 Haskell-MaybeMonad 示例在 F# 中。

这个想法是在两个字典中搜索一个邮件地址。如果两个查找之一返回结果,我们将查看第三个。

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", "billg@microsoft.com")
("Bill Clinton", "bill@hope.ar.us")
("Michael Jackson", "mj@wonderland.org")
("No Pref Guy", "guy@nopref.org")]
|> Map.ofList

let nickNamesDb =
[("billy", "billg@microsoft.com")
("slick willy", "bill@hope.ar.us")
("jacko", "mj@wonderland.org") ]
|> Map.ofList

let prefsDb =
[("billg@microsoft.com", "HTML")
("bill@hope.ar.us", "Plain")
("mj@wonderland.org", "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
}

有更好的解决方案吗?

问候,
fork

最佳答案

您可以在 MaybeBuilder 中实现额外的 Run/Combine 方法,因此结果如下:

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

关于haskell - 在 F# 中实现 Haskell-MaybeMonad - 我们如何才能变得懒惰?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3157154/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com