使用绑定链接连续函数
Use bind to chain continuous functions
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
函数为以下示例链接连续函数?
假设我想将一些数据保存到文件中。如果成功,它应该return保存的数据,如果失败则错误字符串:
首先,我尝试使用 createDirectory
或 createDirectory2
创建一个目录。然后,我尝试使用 both createFile
and 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
我不完全确定 Result
的 F# 库函数是否实现了您在这里所需的一切 - bind
操作允许您按顺序组合多个操作,并在出现第一个错误时停止。
在您的情况下,您想要 运行 两个可能的函数之一,然后您想要执行两个操作并收集它们生成的错误。为此,您可能需要定义更多 Result
函数。这样的事情就可以了(我更改了代码以收集 lists 个错误):
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))
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
函数为以下示例链接连续函数?
假设我想将一些数据保存到文件中。如果成功,它应该return保存的数据,如果失败则错误字符串:
首先,我尝试使用 createDirectory
或 createDirectory2
创建一个目录。然后,我尝试使用 both createFile
and 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
我不完全确定 Result
的 F# 库函数是否实现了您在这里所需的一切 - bind
操作允许您按顺序组合多个操作,并在出现第一个错误时停止。
在您的情况下,您想要 运行 两个可能的函数之一,然后您想要执行两个操作并收集它们生成的错误。为此,您可能需要定义更多 Result
函数。这样的事情就可以了(我更改了代码以收集 lists 个错误):
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))