estamos intentando construir la muestra de Haskell-MaybeMonad desde http://www.haskell.org/all_about_monads/html/maybemonad.html en F #.Implementando Haskell-MaybeMonad en F # - ¿cómo podemos hacer que esto sea flojo?
La idea es buscar un mailaddress en dos diccionarios. Si una de las dos búsquedas devuelve un resultado, buscamos en el tercero.
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
El problema es que realizamos la segunda búsqueda incluso si la primera devuelve un resultado. Lo bueno de Haskell está aquí, que evalúa perezoso. Ahora buscamos algo similar en F #. Probamos el siguiente, pero se ve feo y parece romper la idea de encapsular la lógica tal vez en el constructor:
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
}
¿Hay una solución mejor?
Saludos, forki
Awesome idea. Eso es brillante. – forki23