I find it most useful to define referential transparency in terms of substitution (which is the definition Wikipedia starts with). Namely: if I substitute a function call with its result is there an observable different in program behaviour? If there is, the program is not referentially transparent.
This is clearly the case with `println`.
(println "Hi there")
is clearly not the same program as
nil
as the former causes output to the console, while the latter does not -- an observable difference.
Using Scheme (because I don't know Clojure that well)
(define (foo x)
(let ([y 0])
(set! y 10)
(+ x 1)))
is a referentially transparent program. Although it contains a side-effect (the assignment to y) this effect is not observable outside `foo`, and thus any call to `foo` can be substituted with its result.
Comments
I find it most useful to define referential transparency in terms of substitution (which is the definition Wikipedia starts with). Namely: if I substitute a function call with its result is there an observable different in program behaviour? If there is, the program is not referentially transparent.
This is clearly the case with `println`.
is clearly not the same program as as the former causes output to the console, while the latter does not -- an observable difference.Using Scheme (because I don't know Clojure that well)
is a referentially transparent program. Although it contains a side-effect (the assignment to y) this effect is not observable outside `foo`, and thus any call to `foo` can be substituted with its result.Ah, but
doesn't return nil, it returns a value of the type which can be transparently substituted for the call.Yes, but you're writing in Haskell whereas my example is in Clojure. Hence the difference :)
Dammit! Sorry, carry on!