【问题标题】:Is flow's information loss associated with structural subtyping inherent to this kind of polymorphism?流的信息丢失是否与这种多态性固有的结构子类型相关?
【发布时间】:2017-09-14 19:57:07
【问题描述】:

流中的结构子类型化可能导致信息丢失:

type O = {x: number, y: number};
type P = {x: number, y: number, z: number}

function f(o: O) {
    return o.x * 2, o.y * 2, o;
}

const p: P = {x: 2, y: 3, z: 100};
const r = f(p);

r.z // type error (property not found)

(这段代码很糟糕,因为它执行可见的突变。仅用于说明目的。)

我已经读过,行多态性是一个在不危及类型安全的情况下避免这种信息丢失的概念。

有没有办法通过子类型多态来实现相同的目标?

[编辑]

为了让更多的观众了解,我对这个有点吓人的术语做一个简短的解释:

  • Polymorpishm 只是一个花哨的词,用于确定两种类型是否等价,即它使刚性类型系统更加灵活
  • 参数多态性(流中的泛型)指出两种类型总是等价的,因为类型根本不重要
  • 子类型多态性(流中的子类型)表明如果您可以从中派生层次结构,则两种类型是等价的,即将子类型包含在其超类型下
  • 行多态性类似于子类型化,但解决了信息丢失问题(但从技术上讲,不再存在子类型关系,因此它不是子类型化的一种形式)
  • 有界多态性表明两种类型仅在特定目的下是等价的,例如相等、顺序、映射等。

【问题讨论】:

    标签: javascript polymorphism flowtype subtyping structural-typing


    【解决方案1】:

    对于我所阅读的有关 Flowtype 的内容,我很确定您的功能是问题所在。

    如果您改为这样做:

    function f<T: O>(o: T): T {
      o.x *= 2;
      o.y *= 2;
      return o;
    }
    
    r.z; // okay
    

    这是因为有界多态性。现在在假设 T 是 O 的子类型的情况下检查身体类型。此外,在调用站点之间不会丢失任何信息。 Read more about it here.

    另外,我之前没有听说过行多态,所以我去查了一下。在查找时,我已经阅读了几篇似乎表明行多态性 不是 子类型的内容。 1, 2, 3.

    扩展此答案并澄清为什么 OPs 功能不起作用,但我建议的功能将正常工作。 This is a nice reference as well but is specific to Java.

    通过具有如下功能:

    function f(o: O) {
      return o.x * 2, o.y * 2, o;
    }
    

    该函数指定它正在显式查找 O 类型的对象,而不是 O 的对象或 O 的子类型。在 OPs 函数中,我们将参数 o 向下转换为类型 O,而不是使用泛型(这很糟糕)。处理这个问题的正确方法是利用泛型来指定它可以是 O 类型或 O 的子类型,可以这样做:

    function f<T: O> (o: T): T {
      o.x *= 2;
      o.y *= 2;
      return o;
    }
    

    Check out the docs on how flow handles generics与函数参数、对象等有什么关系。

    相关部分是:

    • “泛型允许您在添加约束的同时保留更具体的类型。通过这种方式,泛型上的类型充当“边界”。link

    • “泛型有时允许您将类似参数的类型传递给函数。这些被称为参数化泛型(或参数多态性)。” link

    【讨论】:

    • 为什么我的函数有问题?它只是依赖于子类型的承诺,即可以将子类型传入任何需要其超类型的地方。您的建议是改用有界多态性。好吧,这只是意味着子类型不如其他形式的多态性 - 至少在某些情况下以及实现可靠算法所需的复杂性方面。
    • @ftor 我明白你在说什么,而且它似乎应该工作,但你有你说的功能,它明确地寻找一个参数O 类型的参数,而不是 O 类型的参数 O 的子类型。指定参数是 你告诉编译器你期望的参数是 O 类型或子类型 O。查看 Java 如何处理它softwareengineering.stackexchange.com/questions/227918/…
    • @ftor 查看我的更新答案,因为它更好地解释了我之前的评论和 OOP,但在流程的上下文中。
    • 为您的努力+1。我认为决定性的线索实际上在你的一个 cmets 中。这是子类型。这是一个面向对象的概念,我试图从 FP 的角度来判断它。就我个人而言,这种隐式向下转换似乎是类型系统子类型部分中的一个错误。好吧,您展示了一个更可靠的替代方案,我将其称为 bounded generics 用于结构类型。这种多态性对我来说比结构子类型更有意义。
    • 我同意它的功能似乎有点奇怪,您可能会争辩说它可以被视为一个错误。当您执行隐式向下转换时,编译器可能会警告您,因为我觉得编码标准应该鼓励人们不要这样做。此外,正如我们通过您的示例所看到的,我觉得隐式向下转换在调试时会导致很多混乱。我没有看到编译器只是警告用户但仍然成功编译程序的问题。
    猜你喜欢
    • 2016-02-16
    • 2018-02-22
    • 2021-01-18
    • 1970-01-01
    • 2021-01-08
    • 1970-01-01
    • 2016-09-22
    • 1970-01-01
    • 2018-09-17
    相关资源
    最近更新 更多