gpt4 book ai didi

f# - F# 4.1 中的新 Result 类型是否有类似于 tryFind 的方法?

转载 作者:行者123 更新时间:2023-12-04 22:56:25 30 4
gpt4 key购买 nike

F# 语言包含有区别的联合类型 option<'T> .几个模块包含有用的功能XYZ.tryFind其返回值为 option<'T> 类型的对象. (例如:List.tryFindMap.tryFindArray.tryFind)。 F# 4.1添加类型 Result<'S,'T>类似于 option<'T>但提供更多信息。是否有类似于 tryFind 的功能对于Result<'S,'T>类型?

下面的代码是创建这样一个函数的尝试。

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""

另外,为什么 [<Struct>]声明出现在 Result 上方对象?

最佳答案

标准库没有这些功能,也不应该。像 tryFind 这样的函数,实际上只有一件事可能出错:找不到值。因此,实际上没有必要对错误情况进行全面的表示。只需一个简单的“是/否”信号就足够了。

但这是一个合法的用例,在已知上下文中,您需要使用特定错误信息“标记”故障,以便您可以将其传递给更高级别的消费者。

但是,对于这个用例,为每个函数发明一个包装器将是浪费和重复的:这些包装器将完全相同,除了它们正在调用的函数。通过使函数成为高阶函数,您的尝试朝着正确的方向前进,但还远远不够:即使您接受该函数作为参数,您也已经“融入”了该函数的形状。当您发现自己需要使用一个具有两个参数的函数时,您将不得不复制并粘贴包装器。这最终来自于您的函数处理两个方面的事实 - 调用函数和转换结果。你不能在没有另一个的情况下重复使用一个。

让我们尝试进一步扩展该方法:将问题分解为更小的部分,然后将它们组合在一起以获得完整的解决方案。

首先,让我们自己发明一种“转换”Option 的方法。值转换为 Result一。显然,我们需要提供错误的值:

module Result =
let ofOption (err: 'E) (v: 'T option) =
match v with
| Some x -> Ok x
| None -> Error err

现在我们可以使用它来转换任何 Option进入 Result :
let r = someMap |> Map.tryFind k |> 
Result.ofOption (sprintf "Key %A couldn't be found" k)

到现在为止还挺好。但是接下来要注意的是,误差值并不总是需要的,所以每次都计算它会很浪费。让我们推迟这个计算:
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)

现在我们仍然可以使用 ofOption当误差值计算成本低时,我们也可以使用 ofOptionWith 推迟计算:
let r = someMap |> Map.tryFind k 
|> Result.ofOptionWith (fun() -> sprintf "Key %A couldn't be found" k)

接下来,我们可以使用这个转换函数来围绕返回 Option 的函数创建包装器。让他们返回 Result :
module Result =
...
let mapOptionWith (err: 'a -> 'E) (f: 'a -> 'T option) a =
f a |> ofOptionWith (fun() -> err a)

现在我们可以定义您的 rF Result.mapOptionWith 方面的功能:
let rF = Result.mapOptionWith
(sprintf "Map.tryFind called on myMap with bad argument %s")
(fun k -> Map.tryFind k myMap)

关于f# - F# 4.1 中的新 Result 类型是否有类似于 tryFind 的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43823743/

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