【问题标题】:Polymorphic lambda calculus多态λ演算
【发布时间】:2016-05-06 18:48:13
【问题描述】:

在非常有启发性的演讲Constraints Liberate 中,Rúnar 说,只有一种方法可以实现具有此签名的函数:

def id[A](a: A): A

嗯,很明显。但是吹毛求疵的人可能会想出一个像

这样的实现
def id[A](a: A): A = {
  if (a.isInstanceOf[Integer])  
    5
  else 
    a
}

好吧,我为什么要关心?

大名鼎鼎的Theorems for free! article中的函数也可以说完全一样的问题,但是我们有functions in the polymorphic lambda calculus的限制,在这种情况下Type-Casing肯定是无效的。

我正在寻找一种精确的方法来明确允许使用 Scala 语言的哪些子集,当我们说类似 “只有一个可能的具有此签名的纯函数实现:”

def id[A](a: A): A

【问题讨论】:

  • 说到 nitpicks,id 的返回值应该是 a,而不是 A :)
  • 再吹毛求疵,if (a.isInstanceOf[Integer]) { 5 } 对 id 完全没有影响。你可能想要的是if (a.isInstanceOf[Integer]) { 5 } else a
  • 你知道什么是“纯函数”吗?
  • @pedrofurla 如果您的意思是_.isInstanceOf[X] 不是纯函数,我不同意。我没有看到任何副作用,输出完全由输入决定。特别是,如果你告诉我 _.isInstanceOf[X] 不是纯函数,那么 _ == _ 也不再是纯函数了。
  • 不,不是那个意思。你知道什么是总函数吗?

标签: scala lambda-calculus


【解决方案1】:

glib 的答案是“由多态 lambda 演算建模的 Scala 子集”:)。

不太流畅,the Scalazzi Safe Scala subset 有一个很好的条件列表。它们在下面复制,稍作修改。

  • 没有null
  • 没有例外
  • 没有类型大小写(_.isInstanceOfcase 匹配),除了一个例外
  • 无类型转换 (_.asInstanceOf)
  • 无副作用
  • 没有.equals (_ == _)、.toString.hashCode
  • 没有 notifywait(我会认为有副作用)
  • 没有classOf.getClass
  • 没有一般递归(更一般地说,所有函数都必须是总的)

“无类型大小写”的一个例外是pattern matching with match ... case on the equivalent of algebraic data types with sealed hierarchies and case classes and case objects。要了解您的特定 match ... case 语句是否被允许,请使用以下规则:

  • 仅在case 语句中使用提取器;不要使用case (x: Int)... 类型匹配。确保您的提取器遵守 Scalazzi 规则(实现这一点的最简单方法是根本不编写提取器,即仅使用编译器提供的 case classcase object 形式的提取器)。
  • 匹配必须涵盖所有可能的情况。这意味着没有 match is not exhaustive 警告,并且您匹配的东西最好是 sealed 的子类型。

这些规则与 Typelevel 博客文章提出的 fold-encoding 规则略有不同,但基本上是等效的(上面的规则更保守,希望更容易记住)。

如果您不能/不想验证这些是否适用于您未编写但使用的所有函数,我发现您自己的代码遵循上述规则,然后不依赖于将Any 作为参数或产生Unit 作为返回类型通常就足够了。

【讨论】:

  • 您的观点是实用的指导,谢谢。但是,我对这个问题的理论方面真的很感兴趣。 @jörg-w-mittags comment goes in this direction. Ruling out reflection as effectful leads to the question of an exact definition of reflective` 表达式。
【解决方案2】:

如果您将注意力限制在引用透明函数上,则该语句是正确的,并且不需要子集。

【讨论】:

  • 限制不是一种“子集化”吗?
  • 可变状态和 I/O 是明显的违规者。一个不那么明显但也必须被禁止的副作用是反射。几年前,Erik Meijer 给出了一个很好的例子,说明如何使用线程实现可变状态,因此也必须禁止这样做。 (副作用真的很讨厌。如果你允许一个,你就会得到所有的!)
  • @jörg-w-mittag:我想你指的是article。非常感谢,这读起来很有趣。 什么是 Scala 中的有效表达式? 这个问题似乎相当复杂,即使对象创建也被认为是有效的......
  • @KlausSchulz:实际上,这是 Channel9 上的一个视频白板会议,但他给出的示例与您挖出的论文中的 Cω 示例相同。这是为了回应 Channel9 论坛上经常出现的 cmets,即 Microsoft 可以“通过删除可变状态使 C♯ 更强大”,而 Erik 的论点有两个方面:a) 你不能通过 removing 一些东西,并且 b) 仅仅删除可变状态将无济于事,因为您可以使用线程模拟可变状态。 (或者,换句话说:从 C♯ 中删除可变状态不仅不会使它变得更多......
  • ... 强大,它也不会让它减弱强大,事实上,它根本没有任何效果!)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-14
  • 1970-01-01
  • 2016-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多