在一个有区别的联合中编码结果类型

时间:2013-09-23 13:07:38

标签: f#

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

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&lt; unit&gt;具有特殊意义。

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 _ 。围绕这个的首选方式是什么?

1 个答案:

答案 0 :(得分: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, _) -> ...