Does Scala have a value restriction like ML, if not then why?
这是我对这个问题的看法。有人能证实、否认或详细说明吗?
我写道:
Scala doesn’t unify covariant
List[A] with a GLB ? assigned toList[Int] , bcz afaics in subtyping"biunification" the direction of assignment matters. ThusNone must have typeOption[⊥] (i.e.Option[Nothing] ), dittoNil typeList[Nothing] which can’t accept assignment from anOption[Int] orList[Int] respectively. So the value restriction problem originates from directionless unification and global biunification was thought to be undecidable until the recent research linked above.
您可能希望查看上述评论的上下文。
ML的值限制将不允许在(以前被认为是罕见的,但可能更普遍的)情况下进行参数多态,否则这样做是合理的(即类型安全的),例如,特别是对于部分应用课程函数(这在函数式编程中很重要),因为可选的类型解决方案创建了一个功能和命令式编程之间的分层以及模块化抽象类型的中断封装。哈斯克尔有一个类似的双重单态限制。在某些情况下,OCAML可以放松限制。我详细阐述了其中的一些细节。
编辑:我在上面的引语中表达的原始直觉(值限制可以通过子类型消除)是不正确的。我的答案很好地阐明了这个问题,我无法决定在包含亚历克赛、安德烈亚斯或我的答案的集合中,哪一个是最好的答案。我觉得他们都是值得的。
正如我前面所解释的,当您将参数多态性与可变引用(或某些其他效果)结合起来时,就需要进行值限制(或类似的事情)。这完全独立于语言是否有类型推断,或者语言是否允许子类型。一个典型的反例
1 2 3 | let r : ?A.Ref(List(A)) = ref [] in r := ["boo"]; head(!r) + 1 |
不受删除类型批注的能力或向量化类型添加绑定的能力的影响。
因此,当您添加对f<:的引用时,您需要施加一个值限制,以避免失去可靠性。同样,MLSUB也无法摆脱价值限制。scala已经通过其语法强制了一个值限制,因为甚至没有办法编写一个具有多态类型的值的定义。
比那简单多了。在scala中,值不能有多态类型,只有方法可以。例如,如果你写
1 |
它的类型不是
如果你采用多态的方法,例如
1 |
并尝试将其赋值
1 | val id1 = id |
编译器将再次尝试(在本例中失败)推断特定的
所以这个问题没有出现。
编辑:
如果你试图复制http://mlton.org/value restriction u替代品来代替scala中的"值限制"示例,你遇到的问题并不是缺乏
这是违法的。如果你写了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
值限制允许的值。
也就是说,scala的规则等价于只允许lambda作为ML中的多态值,而不允许任何值限制。
编辑:此答案以前不正确。我已经完全重写了下面的解释,以便从安德烈亚斯和亚历克赛的回答下面的评论中获得新的理解。好的。
The edit history and the history of archives of this page at archive.is provides a recording of my previous mission and discussion.我选择编辑而不是删除并编写新答案的另一个原因是保留对此答案的评论。在我看来,这个答案仍然是需要的,因为尽管亚历克赛正确、最简洁地回答了主题,但安德烈亚斯的阐述对我获得理解是最有帮助的,但我认为外行读者可能需要一个不同的、更全面的(但希望仍然是生成的本质)解释,以便快速获得一些DEP。理解这个问题。另外,我认为其他的答案掩盖了一个整体性的解释是多么复杂,我希望天真的读者可以选择去品味它。我发现之前的解释并不是用英语描述所有细节,而是(数学家为了提高效率而做的)依靠读者从符号编程语言示例和前提域知识的细微差别中辨别细节(例如,关于编程语言设计的背景事实)。好的。 值限制出现在referenced1类型参数化对象2的突变处。在下面的MLTON代码示例中演示了在没有值限制的情况下会导致的类型不安全:好的。 一种类型复杂的情况出现,以防止(重新)量化(即绑定或确定)所述引用(及其指向的对象)的类型参数(aka类型变量)到一个类型,当重用先前用不同类型量化的所述引用的实例时,该类型会有所不同。好的。 例如,连续函数应用程序(aka调用)重用此类引用的同一个实例时,就会出现这种情况(可以说是令人困惑和费解)。iow,每次应用函数时,引用的类型参数(与对象相关)都被(重新)量化的情况,但是相同的引用实例(及其指向的对象)被重用到函数的每个后续应用(和量化)中。好的。 相切地说,这些现象的出现有时是不直观的,因为缺乏明确的通用量词?(由于隐含的rank-1 prenex词法范围量化可以通过构造(如 安德烈亚斯写道:好的。
Unfortunately, ML does not usually make the quantifiers explicit in its syntax, only in its typing rules.
Ok. 例如,对于与数学符号类似的 值限制是ML的折衷,它可以防止所有不安全的情况,同时也可以防止一些(以前被认为是罕见的)安全的情况,从而简化类型系统。价值限制被认为是一个更好的折衷方案,因为早期(过时?)使用更复杂的类型方法的经验没有限制任何或多个安全案例,导致了命令式编程和纯函数式编程(又称应用程序)之间的分歧,并且泄漏了ML函数模块中抽象类型的一些封装。我引用了一些资料,并在这里详细阐述。不过,切题地说,我在思考早期反对分歧的论点是否真的能站起来反对这样一个事实:名字调用根本不需要值限制(例如,haskell-sique lazy evaluation,当它也被需要记忆时),因为概念上的部分应用程序不会在已经被评估的状态上形成闭包;以及-模块化组合推理需要名称,当与纯度结合时,模块化(范畴理论和等式推理)控制和效果组合。反对按名称调用的单变形限制参数实际上是关于强制类型注释的,但是当需要最佳记忆化(aka sharing)时,显式的说明就不那么麻烦了,因为模块化和可读性无论如何都需要所述注释。按值调用是一种精细的齿梳级别的控制,因此当我们需要低级别的控制时,也许我们应该接受值限制,因为更复杂的类型允许的罕见情况在命令式和应用式设置中会不太有用。但是,我不知道这两者是否可以以平滑/优雅的方式在相同的编程语言中分层/分离。代数效应可以在cbv语言(如ml)中实现,并且可以消除值限制。如果值限制影响到代码,可能是因为编程语言和库缺少处理效果的合适元模型。好的。 scala对所有这些引用都进行了语法限制,这是一种折衷,例如限制与ML的值限制相同甚至更多的情况(如果不限制的话是安全的),但在我们不会为与值限制相关的错误消息感到头疼的意义上,它更为规则。在scala中,我们永远不允许创建这样的引用。因此,在scala中,我们只能表示当引用的类型参数被量化时创建新引用实例的情况。注:OCAML在某些情况下放宽了值限制。好的。 注意,scala和ml都不能声明引用是不可变的1,尽管它们指向的对象可以用 为了使复杂的类型出现,需要引用类型1的可变性的原因是,如果我们用一个非参数化的对象(即不是 啊!如果你不复习相关的例子就理解了这一点,我会印象深刻。好的。型 1imo改为使用短语"可变引用"而不是"被引用对象的可变性","引用类型的可变性"将更容易混淆,因为我们的目的是改变对象的值(及其类型),而该值由指针引用-而不是指指针的可变性。指的是什么。有些编程语言甚至不能明确区分什么时候不允许在基元类型的情况下改变引用或它们指向的对象。好的。型 2其中一个对象甚至可以是一个函数,在允许一级函数的编程语言中。好的。型 3以防止运行时由于访问(读取或写入)被引用对象而出现分段错误,并假定该对象为静态(即编译时)确定的类型,该类型不是对象实际拥有的类型。好的。型 4which are
2
3
4
5