BasicsDecCodeStory_Functions.html
copyright © James Fawcett
Revised: 05/11/2026
4.0 Prologue
In declarative languages, functions are values like any other: they can be stored in
variables, passed as arguments, returned from other functions, and placed in data
structures. This property, called first-class functions, enables a
style of programming where behavior is composed from small, named, reusable pieces
rather than hard-coded into control-flow structures.
4.1 Pure Functions
A pure function depends only on its arguments and returns the same
result for the same inputs with no observable side effects. It is the building block
of declarative composition.
-- Haskell: all functions are pure unless they return IO
double :: Int -> Int
double x = x * 2
clamp :: Ord a => a -> a -> a -> a
clamp lo hi x = max lo (min hi x)
-- Rust: pure functions (no mut, no I/O, no unsafe)
fn double(x: i32) -> i32 { x * 2 }
fn clamp(lo: f64, hi: f64, x: f64) -> f64 { lo.max(hi.min(x)) }
Pure functions are trivially testable (no setup or teardown), safely memoizable, and
trivially parallelizable (no shared state to synchronize).
4.2 First-Class and Higher-Order Functions
First-class functions can appear anywhere a value can appear.
Higher-order functions take functions as arguments or return them as results.
-- Haskell: applyTwice takes a function and a value
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)
applyTwice double 3 -- 12
applyTwice (+3) 10 -- 16
-- F#: function stored in a list
let transforms = [ (*2); (+10); negate ]
transforms |> List.map (fun f -> f 5) // [10; 15; -5]
-- Rust: function pointers and closures as arguments
fn apply_twice(f: impl Fn(i32) -> i32, x: i32) -> i32 { f(f(x)) }
apply_twice(|x| x * 2, 3) // 12
4.3 Function Composition
Composition builds a new function from two existing ones by piping
the output of the first into the input of the second. It is the declarative substitute
for a sequence of variable assignments.
-- Haskell: (.) is the composition operator
-- (f . g) x = f (g x)
normalize :: String -> String
normalize = trim . toLower . removeAccents
-- Applied: normalize " Café " = "cafe"
-- F#: (|>) pipes left-to-right; (>>) composes left-to-right
let normalize = removeAccents >> toLower >> trim
" Café " |> normalize // "cafe"
-- Rust: iterator chaining is functional composition
let result: Vec<String> = words
.iter()
.map(|w| w.to_lowercase())
.filter(|w| !w.is_empty())
.collect();
-- Python: functools.reduce for composition
from functools import reduce
normalize = reduce(lambda f, g: lambda x: g(f(x)),
[remove_accents, str.lower, str.strip])
Composition makes the pipeline explicit and linear: each stage’s name describes
exactly what it does to the data. There are no intermediate variable names obscuring
the transformation sequence.
4.4 Currying and Partial Application
Currying transforms a multi-argument function into a chain of
single-argument functions. Applying a curried function to fewer arguments than it
requires returns a new function that expects the rest - this is
partial application.
-- Haskell: all functions are curried by default
add :: Int -> Int -> Int
add x y = x + y
add5 :: Int -> Int
add5 = add 5 -- partial application; add5 y = add 5 y
map (add 10) [1,2,3] -- [11,12,13]
-- F#: curried by default
let add x y = x + y
let add5 = add 5
[1;2;3] |> List.map add5 // [6;7;8]
-- Rust: partial application via closures (no built-in currying)
let add = |x: i32| move |y: i32| x + y;
let add5 = add(5);
vec![1,2,3].iter().map(|&y| add5(y)).collect::<Vec<_>>()
-- Python: functools.partial
from functools import partial
add5 = partial(lambda x, y: x + y, 5)
list(map(add5, [1, 2, 3])) # [6, 7, 8]
Currying and partial application eliminate the need for many lambda wrappers.
Instead of map (fun x -> add 5 x), you write map (add 5).
This is the foundation of point-free style, covered in Chapter 6.
4.5 Epilogue
Treating functions as values transforms a program from a collection of procedures
into an algebra of transformations. Composition replaces sequencing; partial application
replaces boilerplate wrappers; pure functions replace stateful methods. The next chapter
shows how recursion replaces loops as the mechanism for repetition.
4.6 References
Currying - Wikipedia
Haskell Functions - Tutorial
F# Functions - Microsoft
Python functools.partial