【问题标题】:Purpose of a single case discriminated union单一案件歧视工会的目的
【发布时间】:2012-04-26 09:42:00
【问题描述】:

我正在定义一个单子可观察/反应式解析器。这与普通解析器的行为完全不同,因为它是一个连续查询。底层类型是:

IObservable<'a> -> IObservable<'b>

通过查看函数式语言中的各种解析器实现,似乎更合适的定义事物的方法是单案例区分联合:

type Pattern<'a,'b> = Pattern of (IObservable<'a> -> IObservable<'b>)

这意味着我需要提取底层函数来使用它:

let find (Pattern p) = p

问题是:这只是按照惯例,还是为了以后扩展的目的,或者即使定义永远不会改变也有理由这样做?

额外问题:如果只是为了更方便的类型签名,为什么不直接使用类型别名:

type Pattern<'a,'b> = IObservable<'a> -> IObservable<'b>

我在这方面已经取得了相当大的进展,还没有发现不使用 DU 会影响可组合性的情况。

【问题讨论】:

    标签: f# monads discriminated-union


    【解决方案1】:

    F# 编译器不保留有关类型缩写的信息,因此您根本不会从 类型推断 中受益。类型签名可以理解为程序规范;让类型检查器完成他们的工作是确保程序正确性的好方法。

    在类型别名的情况下,您需要在任何地方显式指定类型注释:

    type Vector = float * float
    
    // val add : float * float -> float * float -> Vector
    let add ((x1, y1): Vector) ((x2, y2): Vector): Vector = (x1 + y1, x2 + y2)
    

    但它不会像使用 DU 那样让您透明:

    type Vector = V of float * float
    
    // val add : Vector -> Vector -> Vector
    let add (V(x1, y1)) (V(x2, y2)) = V(x1 + y1, x2 + y2)
    

    在复杂的程序中,清晰的类型签名确实更容易维护可组合性。

    向单例 DU 添加更多案例不仅更简单,而且使用成员和静态方法扩展 DU 也更容易。一个例子是您经常覆盖ToString() 以获得漂亮的打印效果。

    【讨论】:

    • 谢谢,这实际上是一个非常具体的原因。绝对不想在任何地方都输入IObservable&lt;'a&gt; -&gt; IObservable&lt;'b&gt; 而不是Pattern&lt;'a,'b&gt;
    • 许多个月后的后续行动。我最终确实在联合中添加了第二个案例,因此宇宙处于平衡状态。
    【解决方案2】:

    据我了解,区分大小写的联合类型可以提供与您的问题域语义相关的名称,以及名称为“字符串”的其他通用后端类型。

    这是对语义的轻度抽象泄漏修复,仅此而已,AFAIK

    【讨论】:

    • 我认为这不是真的。这就是类型别名。单例区分联合是一个完整的类,在这种情况下,它包装了一个函数(或 C# 中的委托)。
    • 确实如此。但我不知道除此之外的任何其他用途......另外,请注意您可以向联合类型添加一些方法。
    猜你喜欢
    • 1970-01-01
    • 2011-11-17
    • 2015-01-22
    • 1970-01-01
    • 1970-01-01
    • 2019-05-04
    • 2017-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多