Skip to content

Instantly share code, notes, and snippets.

@vpayno
Last active December 23, 2020 03:57
Show Gist options
  • Save vpayno/eec11d4a837fab1a9024 to your computer and use it in GitHub Desktop.
Save vpayno/eec11d4a837fab1a9024 to your computer and use it in GitHub Desktop.
Haskell Cheat Sheets - Higher Order Functions

By Victor Payno

Higher Order Functions

Curried Functions

"In mathematics and computer science, currying is the technique of translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument." -- Wikipedia

Every function in Haskell officially takes a single argument. That's why arguments are separated with -> instead of commas. The -> symbol means the function returns. The -> symbol is right-associative.

Partial application of a function means calling a function with too few parameters (in our case just 1).

When a function takes multiple parameters, each function is actually taking only one parameter and returning partially applied function until we reach a function that returns a solid value.

multiplyThree :: (Num a) => a -> a -> a -> a
multiplyThree x y z = x * y * z

multiplyThree 3 5 7
> 105

((multiplyThree 3) 5) 7
> 105

When we call a function with too few parameters, we're creating new functions on the fly.

multiplyTwo :: (Num a) => a -> a -> a
multiplyTwo x y = x * y

multiplyByFour :: (Num a) => a -> a
multiplyByFour x = multiplyTwo 4 x

multiplyByFour' :: (Num a) => a -> a
multiplyByFour' = multiplyTwo 4

multiplyByFour 8
> 32

multiplyByFour' 8
> 32

Infix functions can be partially applied by surrounding it with parentheses and only apply a value to one side. That's called applying sections.

addEight :: (Num a) => a -> a
addEight = (+ 8)

addEight 10
> 18

The exception is in how we specify negative numbers! A negative number is not a function that subtracts that number. If you want to specify a function that subtracts that number you need to use the subtract function.

(subtract 4)

Here is an example of a function that takes a function as a parameter and returns a function. We have to use the parenthesis to indicate that.

useTwice :: (a -> a) -> a -> a
useTwice f x = f (f x)

useTwice (max 8) 10
> 10

useTwice (+ 8) 10
> 26

useTwice (3:) [1,2]
> [3,3,1,2]

We can use the last example to implement a function that takes two lists and zips them together without using list comprehension.

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' _ [] _ = []
zipWith' _ _ [] = []
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys

zipWith' (+) [1,2,3] [4,5,6]
> [5,7,9]

zipWith' (min) [5,2,7] [4,3,0]
> [4,2,0]

zipWith' (max) [5,2,7] [4,3,0]
> [5,3,7]

zipWith' (++) ["fifty-", "sixty-", "seventy-"] ["four", "five", "six"]
["fifty-four","sixty-five","seventy-six"]

zipWith' (zipWith' (*)) [[1,2,3],[4,5,6],[7,8,9]] [[9,8,7],[6,5,4],[3,2,1]]
[[9,16,21],[24,25,24],[21,16,9]]

Doing the same thing with list comprehension instead of recursion.

zipWith'' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith'' _ [] _ = []
zipWith'' _ _ [] = []
zipWith'' f xs ys = [(f x y) | (x, y) <- zip xs ys]

zipWith'' (+) [1,2,3] [4,5,6]
> [5,7,9]

zipWith'' (min) [5,2,7] [4,3,0]
> [4,2,0]

zipWith'' (max) [5,2,7] [4,3,0]
> [5,3,7]

zipWith'' (++) ["fifty-", "sixty-", "seventy-"] ["four", "five", "six"]
> ["fifty-four","sixty-five","seventy-six"]

zipWith'' (zipWith'' (*)) [[1,2,3],[4,5,6],[7,8,9]] [[9,8,7],[6,5,4],[3,2,1]]
> [[9,16,21],[24,25,24],[21,16,9]]

Maps & Filters

Lambdas

Folds

Function Application

Function Composition

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment