Implementierung der Haskell-MaybeMonad in F # - wie können wir das faul machen?
Wir versuchen, das Haskell-MaybeMonad-Beispiel aus @ zu erstellehttp: //www.haskell.org/all_about_monads/html/maybemonad.htm in F #.
Die Idee ist, in zwei Wörterbüchern nach einer E-Mail-Adresse zu suchen. Wenn einer der beiden Suchvorgänge ein Ergebnis zurückgibt, untersuchen wir den dritten.
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
Das Problem ist, dass wir die zweite Suche durchführen, auch wenn die erste ein Ergebnis liefert. Das Schöne an Haskell ist, dass es faul bewertet. Jetzt suchen wir nach etwas ähnlichem in F #. Wir haben Folgendes versucht, aber es sieht hässlich aus und scheint die Idee zu brechen, die Vielleicht-Logik im Builder zu verkapseln:
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
}
Gibt es eine bessere Lösung?
Regards, forki