Main programming paradigms include:
- Modifying mutable variables.
- Using assignments and control structures e.g. loops, goto, etc.
is a way of programming without:
- Mutations
- Assignments
- Loops
- or other imperative control structure
- and focus on functions
In FP, functions are first-class citizen, which means:
- They can be defined anywhere, even in other functions.
- They can be passed as an argument to other functions.
- They can be returned as result of a function.
call-by-value has the advantage that it only evaluates every function argument once.
call-by-name has the advantage that a function argument is not evaluated if it is unused in the function body.
call-by-name vs lazy-evaluation
a lazy-evaluated expression is an expression evaluated only once when it's requested, and caches the result.
call-by-name is an evaluation strategy for function arguments, function arguments will only be evaluated if it's in use in the function body.
If an expression terminates in CBV, it terminates in CBN too. The reversed isn't true.
// Example expression that terminates in CBN but doesn't in CBV
def loop: Int = if (true) loop else 1
def callByValue(a: Int, b: Int): Int = if (a > 0) a else b
def callByName(a: Int, b: => Int): Int = if (a > 0) a else b
callByValue(1, loop) // this doesn't terminate
callByName(1, loop) // this terminates
If a function call itself as its last action, the stack-frame can be reused.