Practical use of curried functions?

ⅰ亾dé卋堺 提交于 2019-11-28 20:15:04

One effective use of curried functions is decreasing of amount of code.

Consider three functions, two of which are almost identical:

(define (add a b)
  (action + a b))

(define (mul a b)
  (action * a b))

(define (action kind a b)
  (kind a b))

If your code invokes add, it in turn calls action with kind +. The same with mul.

You defined these functions like you would do in many imperative popular languages available (some of them have been including lambdas, currying and other features usually found in functional world, because all of it is terribly handy).

All add and sum do, is wrapping the call to action with the appropriate kind. Now, consider curried definitions of these functions:

(define add-curried
  ((curry action) +))

(define mul-curried
  ((curry action) *))

They've become considerable shorter. We just curried the function action by passing it only one argument, the kind, and got the curried function which accepts the rest two arguments.

This approach allows you to write less code, with high level of maintainability.

Just imagine that function action would immediately be rewritten to accept 3 more arguments. Without currying you would have to rewrite your implementations of add and mul:

(define (action kind a b c d e)
  (kind a b c d e))

(define (add a b c d e)
  (action + a b c d e))

(define (mul a b c d e)
  (action * a b c d e))

But currying saved you from that nasty and error-prone work; you don't have to rewrite even a symbol in the functions add-curried and mul-curried at all, because the calling function would provide the necessary amount of arguments passed to action.

They can make code easier to read. Consider the following two Haskell snippets:

lengths :: [[a]] -> [Int]
lengths xs = map length xs

lengths' :: [[a]] -> [Int]
lengths' = map length

Why give a name to a variable you're not going to use?

Curried functions also help in situations like this:

doubleAndSum ys = map (\xs -> sum (map (*2) xs) ys

doubleAndSum' = map (sum . map (*2))

Removing those extra variables makes the code easier to read and there's no need for you to mentally keep clear what xs is and what ys is.

HTH.

You can see currying as a specialization. Pick some defaults and leave the user (maybe yourself) with a specialized, more expressive, function.

I think that currying is a traditional way to handle general n-ary functions provided that the only ones you can define are unary.

For example, in lambda calculus (from which functional programming languages stem), there are only one-variable abstractions (which translates to unary functions in FPLs). Regarding lambda calculus, I think it's easier to prove things about such a formalism since you don't actually need to handle the case of n-ary functions (since you can represent any n-ary function with a number of unary ones through currying).

(Others have already covered some of the practical implications of this decision so I'll stop here.)

Using all :: (a -> Bool) -> [a] -> Bool with a curried predicate.

all (`elem` [1,2,3]) [0,3,4,5]

Haskell infix operators can be curried on either side, so you can easily curry the needle or the container side of the elem function (is-element-of).

We cannot directly compose functions that takes multiple parameters. Since function composition is one of the key concept in functional programming. By using Currying technique we can compose functions that takes multiple parameters.

I would like to add example to @Francesco answer.

So you don't have to increase boilerplate with a little lambda.

It is very easy to create closures. From time to time i use SRFI-26. It is really cute.

In and of itself currying is syntactic sugar. Syntactic sugar is all about what you want to make easy. C for example wants to make instructions that are "cheap" in assembly language like incrementing, easy and so they have syntactic sugar for incrementation, the ++ notation.

 t = x + y
 x = x + 1

is replaced by t = x++ + y

Functional languages could just as easily have stuff like.

f(x,y,z) = abc 
g(r,s)(z) = f(r,s,z). 
h(r)(s)(z) = f(r,s,z)

but instead its all automatic. And that allows for a g bound by a particular r0, s0 (i.e. specific values) to be passed as a one variable function.

Take for example perl's sort function which takes sort sub list where sub is a function of two variables that evaluates to a boolean and list is an arbitrary list.

You would naturally want to use comparison operators (<=>) in Perl and have sortordinal = sort (<=>) where sortordinal works on lists. To do this you would sort to be a curried function.
And in fact sort of a list is defined in precisely this way in Perl.

In short: currying is sugar to make first class functions more natural.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!