Is there an analogous to tryFind for the new Result type in F# 4.1?
f#, f#-4.1, option-type
Solution
The standard library doesn't have these functions, and it shouldn't. With a function like `tryFind`, there is really only one thing that could go wrong: the value can't be found. Therefore, there is really no need for comprehensive representation of the error case. Just a simple "yes/no" signal is enough.
But it is a legitimate use case when, in a known context, you need to "tag" the failure with specific error information, so that you can pass it out to your higher-level consumer.
However, for this use case, it would be wasteful and repetitive to invent a wrapper for every function: these wrappers would be completely identical except the function that they're calling. Your attempt goes in the right direction by making your function a higher-order one, but it does not go far enough: even though you're accepting the function as parameter, you've "baked in" the shape of that function. When you find yourself in a need to work with a function of, say, two arguments, you'll have to copy&paste the wrapper. This ultimately comes from the fact that your function takes care of two aspects - calling the function and converting the result. You can't reuse one without the other.
Let's try to stretch the approach further: break up the problem into smaller pieces, then combine them together to get the complete solution.
First, let's just invent ourselves a way to "convert" an `Option` value into a `Result` one. Obviously, we'd need to provide the value of the error:
module Result =
let ofOption (err: 'E) (v: 'T option) =
match v with
| Some x -> Ok x
| None -> Error err
Now we can use this to convert any `Option` into `Result`:
let r = someMap |> Map.tryFind k |>
Result.ofOption (sprintf "Key %A couldn't be found" k)
So far so good. But the next thing to notice is that the error value is not always needed, so it would be wasteful to compute it every time. Let's make this computation deferred:
module Result =
let ofOptionWith (err: unit -> 'E) (v: 'T option) =
match v with
| Some x -> Ok x
| None -> Error (err())
let ofOption (err: 'E) = ofOptionWith (fun() -> err)
Now we can still use `ofOption` when the error value is cheap to compute, but we can also defer the computation by using `ofOptionWith`:
let r = someMap |> Map.tryFind k
|> Result.ofOptionWith (fun() -> sprintf "Key %A couldn't be found" k)
Next up, we can use this conversion function to create wrappers around functions that return `Option` to make them return `Result`:
module Result =
...
let mapOptionWith (err: 'a -> 'E) (f: 'a -> 'T option) a =
f a |> ofOptionWith (fun() -> err a)
Now we can define your `rF` function in terms of `Result.mapOptionWith`:
let rF = Result.mapOptionWith
(sprintf "Map.tryFind called on myMap with bad argument %s")
(fun k -> Map.tryFind k myMap)
Problem
The F# language contains the Discriminated Union type `option<'T>`. Several modules contain useful functions `XYZ.tryFind` whose return value is an object of type `option<'T>`. (Examples: `List.tryFind`, `Map.tryFind`, `Array.tryFind`). `F# 4.1` added the type `Result<'S,'T>` which is analogous to `option<'T>` but provides more information. Are there functions analogous to `tryFind` for the `Result<'S,'T>` type? The code below is an attempt at creating such a function. ``` let resultFind (ef: 'K -> 'T) (tryfind: 'K -> 'M -> 'T option) (m: 'M) (k: 'K) = let y = tryfind k m match y with | Some i -> Result.Ok i | None -> Result.Error (ef k) let fields = [("Email", "jdoe@xyz.com"); ("Name", "John Doe")] let myMap = fields |> Map.ofList let ef k = sprintf "%s %A" "Map.tryFind called on myMap with bad argument " k let rF = resultFind ef Map.tryFind myMap // analogous to tryFind rF "Name" rF "Whatever" val resultFind : ef:('K -> 'T) -> tryfind:('K -> 'M -> 'T option) -> m:'M -> k:'K -> Result<'T,'T> val fields : (string * string) list = [("Email", "jdoe@xyz.com"); ("Name", "John Doe")] val myMap : Map<string,string> = map [("Email", "jdoe@xyz.com"); ("Name", "John Doe")] val ef : k:'a -> string val rF : (string -> Result<string,string>) [<Struct>] val it : Result<string,string> = Ok "John Doe" [<Struct>] val it : Result<string,string> = Error "Map.tryFind called on myMap with bad argument "Whatever"" ``` Also, why does the `[<Struct>]` declaration appear above the `Result` objects?