Why does the use of functions defined in outer scope not break referential transparency?

StackOverflow https://stackoverflow.com/questions/12722554

  •  05-07-2021
  •  | 
  •  

문제

I am learning Haskell. If I understand correctly, a simple function in Haskell is always referentially transparent. I thought it means its output depends only on the arguments passed to it.

But a function f can call another function g, defined in the outer scope. So in that sense, f's return value depends on the definition of g. And the function g is not passed to f as a parameter - at least not explicitly. Doesn't this break referential transparency?

도움이 되었습니까?

해결책

Referential transparency means that

f s = "Hello " ++ g s
g s = s ++ "!"

is indistinguishable from

f s = "Hello " ++ h s
  where h s = s ++ "!"
g s = s ++ "!"

and

f s = "Hello " ++ s ++ "!"
g s = s ++ "!"

It means you can inline g into f without it altering the meaning of f.

If it was going to alter the meaning of f, you would have to alter g somehow. How?

다른 팁

The key is immutability.

I'll illustrate the point by comparison with a language that allows mutability by default - Javascript. Consider the following code:

f = function(x) {
    return x;
}

g = function(y) {
    f = function(x) {
        return x+y;
    }
}

Now you can break referential transparency:

f(1)   -- returns 1
g(10)
f(1)   -- returns 11

We don't have referential transparency because you can't replace calls to f with their value. For example, in the code

console.log(f(1))
g(10)
console.log(f(1))

You might imagine that you can replace both calls to f(1) with their value (1), getting

console.log(1)
g(10)
console.log(1)

i.e. a piece of code that outputs 1 to the console twice. But actually, running the original code outputs 1 and then outputs 11, because of the intervening call to g(10).

This isn't possible in Haskell, because all values are immutable. In other words, in Haskell you can't write the function g which modifies the value of another function outside its scope. In Haskell, you can always replace function calls with their value without breaking your code.

If g is not passed as a parameter, then it is a "top-level declaration". And such declarations cannot change at run-time. The only way they can change is if you recompile the program.

Thus, the only way a function can yield a different result at run-time is if its declared inputs change. It "depends on" several other things, but none of these other things can change at run-time.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top