[Haskell Cheat Sheets] (https://gist.github.com/vpayno/0a7db3ff9a4fac8774c5)
"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]]