20

I've been reading lots of articles on currying, but almost all of them are misleading, explaining currying as a partial function application and all of examples usually are about functions with arity of 2, like add function or something.

Also many implementations of curry function in JavaScript makes it to accept more than 1 argument per partial application (see lodash), when Wikipedia article clearly tells that currying is about:

translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument (partial application)

So basically currying is a series of partial applications each with a single argument. And I really want to know real uses of that, in any language.

Roman Liutikov
  • 1,338
  • 10
  • 17

3 Answers3

6

Real use case of currying is partial application.

Currying by itself is not terribly interesting. What's interesting is if your programming language supports currying by default, as is the case in F# or Haskell.

You can define higher order functions for currying and partial application in any language that supports first class functions, but it's a far cry from the flexibility you get when every function you get is curried, and thus partially applicable without you having to do anything.

So if you see people conflating currying and partial application, that's because of how closely those concepts are tied there - since currying is ubiquitous, you don't really need other forms of partial application than applying curried functions to consecutive arguments.

scrwtp
  • 13,437
  • 2
  • 26
  • 30
  • 4
    As someone who has been in OP's position and recently come to see the appeal of currying, I couldn't agree more with this answer. After reading https://drboolean.gitbooks.io/mostly-adequate-guide/content/ch4.html and http://ramdajs.com/0.17/docs/#curry , things make sense! It's all about having every function curried by default, which opens the door to using partially applied functions as 'building blocks' in your code. – TW80000 Sep 24 '15 at 04:04
6

It is usefull to pass context.

Consider the 'map' function. It takes a function as argument:

map : (a -> b) -> [a] -> [b]

Given a function which uses some form of context:

f    : SomeContext -> a -> b

This means you can elegantly use the map function without having to state the 'a'-argument:

map (f actualContext) [1,2,3]

Without currying, you would have to use a lambda:

map (\a -> f actualContext a) [1,2,3]

Notes:

map is a function which takes a list containing values of a, a function f. It constructs a new list, by taking each a and applying f to it, resulting in a list of b

e.g. map (+1) [1,2,3] = [2,3,4]

Pieter
  • 777
  • 5
  • 17
2

The bearing currying has on code can be divided into two sets of issues (I use Haskell to illustrate). Syntactical, Implementation.

Syntax Issue 1:

Currying allows greater code clarity in certain cases. What does clarity mean? Reading the function provides clear indication of its functionality. e.g. The map function.

map : (a -> b) -> ([a] -> [b])

Read in this way, we see that map is a higher order function that lifts a function transforming as to bs to a function that transforms [a] to [b].

This intuition is particularly useful when understanding such expressions.

map (map (+1))

The inner map has the type above [a] -> [b]. In order to figure out the type of the outer map, we recursively apply our intuition from above. The outer map thus lifts [a] -> [b] to [[a]] -> [[b]].

This intuition will carry you forward a LOT. Once we generalize map over into fmap, a map over arbitrary containers, it becomes really easy to read expressions like so (Note I've monomorphised the type of each fmap to a different type for the sake of the example).

showInt : Int -> String
(fmap . fmap . fmap) showInt : Tree (Set [Int]) -> Tree (Set [String])

Hopefully the above illustrates that fmap provides this generalized notion of lifting vanilla functions into functions over some arbitrary container.

Syntax Issue 2:

Currying also allows us to express functions in point-free form.

nthSmallest : Int -> [Int] -> Maybe Int
nthSmallest n = safeHead . drop n . sort

safeHead (x:_) = Just x
safeHead _     = Nothing

The above is usually considered good style as it illustrates thinking in terms of a pipeline of functions rather than the explicit manipulation of data.

Implementation:

In Haskell, point free style (through currying) can help us optimize functions. Writing a function in point free form will allow us to memoize it.

memoized_fib :: Int -> Integer
memoized_fib = (map fib [0 ..] !!)
    where fib 0 = 0
          fib 1 = 1
          fib n = memoized_fib (n-2) + memoized_fib (n-1)


not_memoized_fib  :: Int -> Integer
not_memoized_fib x = map fib [0 ..] !! x
    where fib 0 = 0
          fib 1 = 1
          fib n = not_memoized_fib (n-2) + not_memoized_fib (n-1)

Writing it as a curried function as in the memoized version treats the curried function as an entity and therefore memoizes it.

dfeuer
  • 48,079
  • 5
  • 63
  • 167