类方法和闭包中的Scala中的纯函数

时间:2016-03-30 16:43:46

标签: scala functional-programming

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

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

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

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

关于关闭的类似问题:

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

对我而言,两者都是纯粹的功能,相当于一个" 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中纯函数的精确定义是什么?

1 个答案:

答案 0 :(得分:4)

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

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

请注意,局部可变状态也不一定会危及纯度。这是一个很滑的地形,但Martin Odersky曾经说过一次(我可以挖掘出确切的来源,如果我真的必须,它可以是一个关于Coursera课程的讲座,也可以预订Scala编程),vars就可以了。你让它们对外界看不见。所以这个愚蠢的功能:

def addOne(i: Int) = {
  var s = i
  s = s + 1
  s
}
即使它使用可变状态(变量s),

也可以被认为是纯粹的,因为可变状态不会暴露给外部世界"并没有把方法addOne的引用透明度置于危险之中。