Result type是F#4.1中的新功能:
type Result<'T,'TError> =
| Ok of 'T
| Error of 'TError
bind : ('T -> Result<'U, 'TError>) -> Result<'T, 'TError> -> Result<'U, 'TError>
如何使用Result.bind
函数链接下面示例中的连续函数?
假设我想将一些数据保存到文件中。如果成功,它应该返回保存的数据,如果失败则返回错误字符串:
首先,我尝试使用 createDirectory
或 createDirectory2
创建目录。然后,我尝试使用 {/ strong> createFile
和 getPermissionType
函数创建文件。最后,我将数据保存到文件中。
let init data directoryPath =
(match createDirectory directoryPath with
| Ok directory -> Ok directory
| Error err1 ->
match createDirectory2 directoryPath with
| Ok directory -> Ok directory
| Error err2 -> Error (err1 + "; " + err2))
|> function
| Ok directory ->
match (createFile directory directoryPath), (getPermissionType directory) with
| Ok filePath, Ok permissionType ->
Ok (saveData data directory filePath permissionType)
| Error err1, Ok _ -> Error err1
| Ok _, Error err2 -> Error err2
| Error err1, Error err2 -> Error (err1 + "; " + err2)
| Error err -> err
答案 0 :(得分:2)
我不完全确定Result
的F#库函数是否实现了您所需要的所有功能 - bind
操作允许您按顺序组合多个操作,并在第一个错误时停止。
在您的情况下,您希望运行两个可能的功能之一,然后您想要执行两个操作并收集它们生成的错误。为此,您可能需要定义更多Result
函数。这样的事情就是诀窍(我改变了代码来收集错误的列表):
module Result =
let either f1 f2 =
match f1 () with
| Ok res -> Ok res
| Error e1 ->
match f2 () with
| OK res -> Ok res
| Error e2 -> (e1 @ e2)
let both res1 res2 =
match res1, res2 with
| Ok r1, Ok r2 -> Ok (r1, r2)
| Error e1, Error e2 -> Error (e1 @ e2)
| Error e, _ | _, Error e -> Error e
现在您可以按如下方式表达您的逻辑:
let init data directoryPath =
Result.either
(fun () -> createDirectory directoryPath)
(fun () -> createDirectory2 directoryPath)
|> Result.bind (fun directory ->
Result.both (createFile directory directoryPath) (getPermissionType directory))
|> Result.map (fun (filePath, permissionType) ->
saveData data directory filePath permissionType))