2

我有多个代码块,它们要么以不可恢复的错误结束,要么被用户输入取消,要么为下一个代码块提供输入值。那么如何处理最后一步,即Success(所有计算成功完成)。

type Res<'T> =
| Next of 'T
| Cancel
| Fail of string

module Res =
    let bind arg f =
        match arg with
        | Next x -> f x
        | Cancel -> Cancel
        | Fail x -> Fail x

我现在可以像这样将这些步骤串在一起,唉,类型 Res<unit> 具有特殊的含义。

let (|?>) = Res.bind

firstFunc() 
|?> fun intermediateResult ->
    secondFunc intermediateResult
    ...
    |?> fun otherResult ->
        lastFunc otherResult
|> function
| Fail msg -> printfn "Error: %s" msg
| Cancel -> printfn "Cancelled"
| Next() -> printfn "Succeeded"

如果我将Success编码为离散的替代方案,我将在最后一个子句中使用额外的案例Next _ 。解决这个问题的首选方法是什么?

4

1 回答 1

4

我认为你的Next of 'TSuccess of 'T代表几乎相同的东西——它们意味着一个计算块完成并返回了一些值。出于可组合性的原因,计算块是否是整个链中的最后一个并不重要 - 原则上,计算块的行为应该是相同的,无论它是在开头还是结尾你的管道。

但是,如果您想区分这两种情况(并且如果这在组成块时不会影响属性),那么我可能会Success遇到带有附加标志的情况:

type ResultKind = Success | Next
type Result<'T> =
  | Completed of 'T * ResultKind
  | Cancel
  | Fail of string

现在您可以使用它Completed(42, Success)来创建最终值(并Completed(42, Next)立即创建结果)。

在模式匹配中,您可以忽略标志而只写| Completed(result, _) -> ...

于 2013-09-23T14:15:59.663 回答