functional programming programming paradigms immutability pure functions higher-order functions recursion lambda calculus lazy evaluation algebraic data types pattern matching map reduce concurrency parallelism javascript python haskell scala elixir software engineering testing