For example, something as simple as assigning a variable has so much more meaning and functionality than I am used to, thanks to pattern matching.
I look forward to diving deeper into functional programming. Thanks for posting.
For example, something as simple as assigning a variable has so much more meaning and functionality than I am used to, thanks to pattern matching.
I look forward to diving deeper into functional programming. Thanks for posting.
Functional programming tends to take this even further, by eliminating variable assignment to some degree or another. Different languages approach this differently, for instance:
- Erlang (and I assume this extends to Elixir) asserts a variable's value, rather than assigning it. You can see how this works by attempting to assign another value to the same variable: it will throw an error.
- Clojure (and I assume most lisps?) bind a variable to a symbol, but that only applies to the code that follows; if you access a binding, then rebind it, the previous access will only reference the original value. (Clojure, being impure, has ways around this in a bunch of ways.)
Once I grokked FP, I started thinking about this the other way around. If I see code like this in FP:
x = 5;
foo
I read this as "evaluate 'foo', substituting 'x' with '5'" (accounting for shadowing, etc.). In other words, it's sugar for "let x = 5 in foo", or "(lambda x. foo) 5".In contrast, I read the same 2 lines in an imperative program as "first update the contents of memory location 'x' to contain '5', then evaluate 'foo'". This is much more complicated (i.e. has more meaning/function) than the FP version:
- We're specifying an evaluation order (do this, then do that), whilst the FP version works with any evaluation order. Among other things, this makes it difficult to evaluate in parallel (imagine if '5' were 'someExpensiveCalculation' and 'foo' were 'anotherExpensiveCalculationWhichMightNotUseTheFirst').
- We need a notion of "memory cells", which don't follow the lexical/syntactic nature of scoped variables; i.e. the first line may affect references in a seemingly separate piece of code. This makes reasoning much harder (although techniques like separation logic can make many common cases easier).
- The 'foo' calculation may affect the contents of 'x', so we can't trust the "equation" 'x = 5' to hold after (or even part-way-through!) the evaluation of 'foo'
One nice approach is "static single assignment"; it looks imperative (e.g. "single assignment C" looks like C), but it follows the FP semantics. In other words, it's useful when you want to show that your code is "straightforward": if you write it in C, the maintainer/compiler might guess that it's straightforward (e.g. that you don't invalidate the "x = 5") but doesn't know; in single assignment C, they know because the compiler enforces it.