实际使用咖喱功能?

Phi*_*yfi 29 lisp scheme haskell functional-programming currying

有很多关于如何理解函数的教程,以及stackoverflow中的许多问题.然而,在阅读了The Little Schemer,几本书,教程,博客文章和stackoverflow主题之后,我仍然不知道这个简单问题的答案:"有什么关系?" 我明白如何理解一个功能,而不是"为什么?" 在它背后.

有人可以向我解释一下curried函数的实际用法(在每个函数只允许一个参数的语言之外,使用currying的必要性当然非常明显.)

编辑:考虑到TLS的一些例子,有什么好处

(define (action kind)
    (lambda (a b)
        (kind a b)))
Run Code Online (Sandbox Code Playgroud)

而不是

(define (action kind a b)
    (kind a b))
Run Code Online (Sandbox Code Playgroud)

我只能看到更多的代码,没有更多的灵活性......

Yas*_*aev 24

curried函数的一个有效用途是减少代码量.

考虑三个函数,其中两个几乎相同:

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

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

(define (action kind a b)
  (kind a b))
Run Code Online (Sandbox Code Playgroud)

如果你的代码调用add,它依次调用action与实物+.同样的mul.

您定义了这些函数,就像您在许多命令式流行语言中所做的那样(其中一些已经包括lambdas,currying和其他通常在功能世界中发现的功能,因为它们都非常方便).

All addand sumdo,action用适当的方式包含调用kind.现在,考虑这些函数的curried定义:

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

(define mul-curried
  ((curry action) *))
Run Code Online (Sandbox Code Playgroud)

它们变得相当短.我们只是action通过传递一个参数来调整函数kind,并且得到了接受其余两个参数的curried函数.

这种方法允许您编写更少的代码,具有高级别的可维护性.

试想一下,函数action会立即被重写以接受另外三个参数.没有currying你将不得不重写你的实现addmul:

(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))
Run Code Online (Sandbox Code Playgroud)

但是,currying使你免于那些令人讨厌且容易出错的工作; 你不必重写的功能,甚至一个符号add-curried,并mul-curried在所有的,因为调用函数将提供传递给参数的必要量action.


Bil*_*ill 11

它们可以使代码更易于阅读.考虑以下两个Haskell代码段:

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

lengths' :: [[a]] -> [Int]
lengths' = map length
Run Code Online (Sandbox Code Playgroud)

为什么要给你不会使用的变量命名?

Curried函数也有助于这样的情况:

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

doubleAndSum' = map (sum . map (*2))
Run Code Online (Sandbox Code Playgroud)

删除这些额外的变量使代码更容易阅读,并且您无需在心理上清楚地知道x是什么以及y是什么.

HTH.

  • Haskell的部分应用比明确的currying更酷. (4认同)
  • 以无点或默认方式编程不需要curried函数.例如,可以使用组合器来完成.所述风格在J编程语言中很突出.在J currying默认情况下不会发生,默认形式永远不会依赖它. (2认同)