Referential transparency means that when we bind an expression to a name (e.g. `y = f x`), the two are interchangeable, and whenever we use `y` we could just as well use `f x` and vice versa, and the meaning of the code will stay the same.
Enforcing referential transparency in a programming language means that:
- We need to have more control over effects (purity)
- We can use substitution and equational reasoning
The value of referential transparency for me is that I can trust code to not surprise me with unexpected effects, I can use substitution to understand what a piece of code is doing, and I can always refactor by converting a piece of code to a new value or function because referential transparency guarantees that they are equivalent.
Because of that I feel like I can always understand how something works because I have a simple process to figure things out that doesn't require me keeping a lot of context in my head. I never feel like something is "magic" that I cannot understand. And I can easily change code to understand it better without changing its meaning.
Referential transparency is freeing, and makes me worry less when working with code!
---
The other part that is very notable about Haskell is one of its approaches to concurrency - Software Transactional Memory. Which is enabled by limiting the kind of effects we can perform in a transaction block:
https://www.oreilly.com/library/view/parallel-and-concurrent...
Haskellers (including myself) tend to default to STM to take advantage of atomicity.
Of course it's easy to make the safe choice when the shared interface between concurrency primitives make switching very low cost.
More: https://www.oreilly.com/library/view/parallel-and-concurrent...
"Parallel and Concurrent Programming in Haskell" (2013)
https://www.oreilly.com/library/view/parallel-and-concurrent...
https://www.oreilly.com/library/view/parallel-and-concurrent...
[0]: http://shop.oreilly.com/product/0636920026365.do
[1]: https://www.youtube.com/watch?v=N6sOMGYsvFA&list=PLbgaMIhjbm...