简体   繁体   中英

Pure function in Scala in the context of class methods, and closures

What is the precise definition of pure function in Scala? Pure function has a definition, on wiki https://en.wikipedia.org/wiki/Pure_function . I think this definition is for a pure functional programming language.

However, I think it becomes complicated in the context of class method and closure.

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

Is ave a pure function? I think it is, because it has no side effect and it depends only on the immutable state of the class. But this actually violates the pure function definition on wiki, which says pure function generally should not access non-local variable.

Similar question on closure:

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

To me, both ave are pure function, and equivalent to a "val" (Unified Access Principle).

But how to rigorously justify? Moreover, if the a and b fields are mutable, ave is no longer pure functional.

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

Another definition of pure function come from "Function programming in Scala" book:

An expression e is referentially transparent if, for all programs p, all occurrences of e in p can be replaced by the result of evaluating e without affecting the meaning of p. A function f is pure if the expression f(x) is referentially transparent for all referentially transparent x

Then the question is, for a class, is a mutable state in a class referentially transparent( var a, var b in my example)? (If it is, then the ave method in Ave2 becomes pure function, which is a contradiction)

What is the precise definition of a pure function in Scala?

Short answer:
Closures do not prevent purity as long as the closed-over variables are immutable.

Long answer:
In a truly functional programming language non-local variables will never change, so having a closure doesn't affect purity. Haskell functions are pure and yet Haskell uses closures without trouble. As long as your function obeys the rule of not having side-effects and having the same result for the same set of parameters every time it is invoked (in other words, not having mutable state), you get the referential transparency and thus purity. If you're nitpicking on the theoretical view on things, then I completely understand worrying about closures since pure functions should depend on their arguments and their arguments only (not necessarily all of them though). But from a practical viewpoint, closing over immutable variables is not considered to be violating purity.

Note that local mutable state doesn't necessarily endanger purity either. This is a slippery terrain, but Martin Odersky said himself one time (I can dig out the exact source if I really must, it was either a lecture on one of the Coursera courses or book Programming in Scala) that vars are ok as long as you keep them invisible to the outside world. So this silly function:

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

can be considered pure even though it uses mutable state (variable s ) because the mutable state is not exposed to the "outside world" and doesn't put the referential transparency of method addOne in danger.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM