Function
Guards
Guards are a way to define a function by pattern matching on the input arguments. They are defined by a series of boolean expressions.
max' :: Int -> Int -> Int
max' x y
| x > y = x
| otherwise = y
fac n
| n <= 1 = 1
| otherwise = n * fac (n-1)
let
and where
In functions, let
and where
can be used to declare local expression aliases
in a function.
inRange l r x =
let in_lower_bound = l <= x
in_upper_bound = r >= x
in
in_lower_bound && in_upper_bound
inRange l r x =
in_lower_bound && in_upper_bound
where
in_lower_bound = l <= x
in_upper_bound = r >= x
Accumulator
Accumulator is a common pattern in functional programming to avoid stack overflow when using recursion. It's also known as tail recursion.
fac n = aux n 1 -- `aux` is a helper function
where
aux n acc -- `aux` is declared here, and `acc` is the accumulator
| n <= 1 = acc
| otherwise = aux (n - 1) (n * acc)
Higher Order Function
A higher order function is a function that takes a function as an argument or returns a function as a result.
app :: (a -> b) -> a -> b -- `app` takes a function `a -> b` and an argument `a`
app f x = f x -- and returns a result `b`
add1 x = x + 1
app add1 1 -- 2
Lambda Function
Lambda function is an anonymous function that is created using the \
symbol.
(\x -> x + 1) 1 -- 2
(\x y -> x + y) 1 2 -- 3
-- as first-class citizens, lambda functions can be bind to a name
add = \x y -> x + y
Currying
In Haskell, any function can be rewritten to take only one argument:
-- the function that takes 3 args
f :: a -> b -> c -> d
-- can be written as:
f :: a -> (b -> (c -> d))
-- a func that takes 1 arg and returns a func that takes 1 arg
-- which returns a func that takes 1 arg and returns the result
Partial Application
Partial application is the process of supplying a function with fewer arguments than it requires, resulting in a new function that takes the remaining arguments.
add :: Int -> Int -> Int
add = (\x -> (\y -> x + y))
map :: (a -> b) -> [a] -> [b]
doubleList :: [Int] -> [Int]
doubleList = map (\x -> x * 2)
Folding
Folding is a way to reduce a list to a single value. It takes a binary function,
a starting value, and a list to fold up. In Haskell, there are two folding
functions: foldl
and foldr
.
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr (+) 0 [1, 2, 3] -- 1 + (2 + (3 + 0)) = 6
sum = foldr (+) 0
and = foldr (&&) True
or = foldr (||) False
length = foldr (\x -> (+) 1) 0
length = foldr (const $ (+) 1) 0
map f = foldr ((:) . f) []
-- https://wiki.haskell.org/Fold#List_folds_as_structural_transformations
foldr (\x acc -> <term>) <start_acc> <list>
foldl (\acc x -> <term>) <start_acc> <list>