Skip to content
AgileLogics
6 min read

Currying and Partial Application

Prerequisites: Defining functions

Every Haskell function takes exactly one argument. A "two-argument" function is really a function that takes the first argument and returns a function that takes the second. This is called currying.

The type Int -> Int -> Int actually means Int -> (Int -> Int): -> groups to the right.

Partial application

Because of currying, you can give a function some of its arguments and get back a function waiting for the rest:

add :: Int -> Int -> Int
add x y = x + y

addTen :: Int -> Int
addTen = add 10

main :: IO ()
main = do
  print (addTen 5)
  print (map (add 100) [1, 2, 3])
  print (map (max 5) [1, 7, 3, 9])
15
[101,102,103]
[5,7,5,9]

add 10 is a complete value of type Int -> Int. Partial application makes it easy to build new functions from existing ones without writing lambdas.

Operator sections

Operators can be partially applied too, by wrapping them in parentheses with one side missing — a section:

main :: IO ()
main = do
  print (map (* 2) [1, 2, 3])
  print (map (2 ^) [1, 2, 3])
  print (map (^ 2) [1, 2, 3])
  print (map (10 -) [1, 2, 3])
  print (filter (> 3) [1, 5, 2, 8])
  print (map (`div` 2) [10, 11, 12])
[2,4,6]
[2,4,8]
[1,4,9]
[9,8,7]
[5,8]
[5,5,6]
  • (* 2) means \x -> x * 2; (2 ^) means \x -> 2 ^ x. Which side is missing decides where the argument goes.
  • (- 1) is not a section — it's the number minus one. Use subtract 1 instead.

Why it matters

Currying is why Haskell code tends to put the "configuration" arguments first and the data last: map f xs, filter p xs, take n xs. That order makes partial application natural:

firstThree :: [a] -> [a]
firstThree = take 3

main :: IO ()
main = do
  print (firstThree "Haskell")
  print (firstThree [10, 20, 30, 40, 50])
"Has"
[10,20,30]

Defining a function without naming its argument, like firstThree = take 3, is called point-free style.

curry and uncurry

uncurry turns a curried function into one that takes a pair, and curry does the opposite:

main :: IO ()
main = do
  print (uncurry (+) (3, 4))
  print (map (uncurry max) [(1, 5), (8, 2)])
  print (curry fst 'a' 'b')
7
[5,8]
'a'