【问题标题】:Pure function in Scala in the context of class methods, and closures在类方法和闭包的上下文中,Scala 中的纯函数
【发布时间】:2016-07-18 19:32:22
【问题描述】:

Scala 中纯函数的准确定义是什么?纯函数在 wiki https://en.wikipedia.org/wiki/Pure_function 上有一个定义。我认为这个定义是针对纯函数式编程语言的。

但是,我认为它在类方法和闭包的上下文中变得复杂。

class Ave(val a: Int, val b: Int) {
   def ave = (a+b)/2
}

ave 是纯函数吗?我认为是,因为它没有副作用,并且只取决于类的不可变状态。但这实际上违反了 wiki 上的纯函数定义,即纯函数通常不应该访问非局部变量。

关于关闭的类似问题:

def fcn(a:Int, b: Int): Unit = {
    def ave = (a+b) / 2
}

对我来说,两个 ave 都是纯函数,相当于一个“val”(统一访问原则)。

但是如何严格证明呢?此外,如果 a 和 b 字段是可变的,则 ave 不再是纯函数式的。

class Ave2(var a: Int, var b: Int) {
   def ave = (a+b)/2 // Not pure functional
}

纯函数的另一种定义来自《Scala 中的函数编程》一书:

如果对于所有程序 p,表达式 e 是引用透明的, p 中所有出现的 e 都可以替换为求值结果 e 不影响 p 的含义。一个函数 f 是纯的,如果 表达式 f(x) 对所有引用透明的 透明x

那么问题是,对于一个类,一个类中的可变状态是否具有引用透明性(在我的示例中为 var a, var b)? (如果是,那么Ave2中的ave方法就变成了纯函数,这是矛盾的)

Scala 中纯函数的准确定义是什么?

【问题讨论】:

    标签: scala functional-programming


    【解决方案1】:

    简答:
    只要封闭变量是不可变的,闭包就不会阻止纯度。

    长答案:
    在真正的函数式编程语言中,非局部变量永远不会改变,因此闭包不会影响纯度。 Haskell 函数是纯函数,但 Haskell 使用闭包没有问题。只要您的函数遵守没有副作用并且每次调用时对同一组参数具有相同结果的规则(换句话说,没有可变状态),您就可以获得引用透明度,从而获得纯度。如果您对事物的理论观点挑剔,那么我完全理解对闭包的担忧,因为纯函数应该仅依赖于它们的参数和它们的参数(尽管不一定是所有参数)。但是从实际的角度来看,关闭不可变变量并不被认为是违反纯度的。

    请注意,本地可变状态也不一定会危及纯度。这是一个湿滑的地形,但 Martin Odersky 曾经说过自己(如果我真的必须的话,我可以挖掘出确切的来源,它要么是关于 Coursera 课程之一的讲座,要么是《Scala 编程》一书)只要只要你让它们对外界不可见。所以这个愚蠢的功能:

    def addOne(i: Int) = {
      var s = i
      s = s + 1
      s
    }
    

    即使它使用可变状态(变量s)也可以被认为是纯粹的,因为可变状态不会暴露给“外部世界”并且不会使方法addOne的引用透明性处于危险之中。

    【讨论】:

    • 感谢您的回答!我认为这讲的是闭包部分,方法呢,比如上面的 Ave 类?是否适用相同的规则? Haskell有类和方法的概念吗?
    • 是的,同样适用。为什么不?在那种情况下,ave 是一个方法,而不是一个函数,所以你不能期望它在不同的对象上调用时有相同的结果。但是对同一个对象的调用总是会产生相同的结果。至于 Haskell,不,那里没有经典的 OOP 概念。有类型类,但那是不同的(顺便说一句,你也可以在 Scala 中使用参数化特征和它们的隐式实现为各种类型建模类型类,但这是题外话)。
    • 你能说'this'是每个成员函数的参数,因此它是纯粹的,因为它是参数状态(由'this'表示)之间的1:1映射吗?
    猜你喜欢
    • 2011-02-07
    • 1970-01-01
    • 2018-03-24
    • 2017-09-19
    • 2011-02-01
    • 2020-06-24
    • 2020-01-21
    • 1970-01-01
    • 2013-02-04
    相关资源
    最近更新 更多