tratar rebelde quitarle que perezosos para niños muy memes irresponsable hijos hijo hago generacion flojos flojo flojera estudiar cristal como años adultos adulto adolescente haskell f# monads maybe

haskell - rebelde - niños perezosos para estudiar



Implementando Haskell-MaybeMonad en F#- ¿cómo podemos hacer que esto sea flojo? (2)

estamos intentando construir la muestra Haskell-MaybeMonad de http://www.haskell.org/all_about_monads/html/maybemonad.html en F #.

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 lo siguiente, pero parece 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 mejor solución?

Saludos, forki


Puede implementar métodos adicionales Run / Combine en MaybeBuilder para que el resultado sea el siguiente:

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


Siempre hay Lazy , que es efectivamente lo que tienes aquí pero con una sintaxis diferente:

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 }