Functional Programming

Functions must have a singular mapping Functional programming languages want to adhere to that one strict rule - given a particular input, you will always get the same deterministic output back This makes it very easy to debug programs!

Programming Paradigm: classification of programming approach based on behavior of code

  • Typically used interchangibly with language features
  • Python is imperative, object-oriented, and technically functional
  • Ocaml is imperative, object-oriented, and functional - but focuses mostly on functional

Features of Functional Languages

  • Immutable state
  • Declarative programming
  • Referential transparency
  • Realistic about the machine Program state: state of the machine at any given time Typically described as the contents of variables
# imperative.py
x = x + 1
a[0] = 42

Imperative means state is mutable, changing or destructive Can cause side effects (which is bad) Consider:

count = 0
def f(node)
	global count
	node.data = count
	count += 1
	return count
end

No referential transparency (replacing expression with value with no side effects)! i.e. f(x) + f(x) + f(x) != 3 * f(x) != 1 + 2 + 3

Declarative programming: abstract away a lot (Declarative programming is a non-imperative style of programming in which programs describe their desired results without explicitly listing commands or steps that must be performed. Functional and logic programming languages are characterized by a declarative programming style.)

def evens(arr):
	ret = [x for x in arr if x % 2 == 0]
	return ret

Functions and Expressions

Everything is an expression (1-28-2025 - OCaml) Every expression has a type - we can chain these together to also work with nesting

4 + 5
(+) 4 5 (* these are equivalent *)
 
(+) ((+) 4 5) 7 (* 16, nesting of expressions *)

If Expression

(if e1:bool then e2:t else e3:t):t
if e1 then e2 else e3

Static type checking - type checking occurs at compile time Dynamic type checking - when type checking occurs at run time

Let Expression

(let var = e1:t1 in e2:t2):t2
let x = 5 in x + 6

Functions

let f x1 x2 ... xn = ......
let ite g t f = if g then t else f;;
(* val ite : bool -> 'a -> 'a -> 'a = <fun> *)