Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell curried函数的实际使用?_Haskell_Functional Programming_Lisp_Scheme_Currying - Fatal编程技术网

Haskell curried函数的实际使用?

Haskell curried函数的实际使用?,haskell,functional-programming,lisp,scheme,currying,Haskell,Functional Programming,Lisp,Scheme,Currying,stackoverflow上有很多关于如何使用函数的教程,也有很多问题。然而,在阅读了《小阴谋家》、几本书、教程、博客文章和stackoverflow线程之后,我仍然不知道这个简单问题的答案:“咖喱有什么意义?”我确实理解如何咖喱函数,只是不知道它背后的“为什么” 有人能给我解释一下咖喱函数的实际用途吗(除了每个函数只允许一个参数的语言之外,使用咖喱函数的必要性当然很明显。) 编辑:考虑到TLS中的一些示例,使用 (define (action kind) (lambda (a b)

stackoverflow上有很多关于如何使用函数的教程,也有很多问题。然而,在阅读了《小阴谋家》、几本书、教程、博客文章和stackoverflow线程之后,我仍然不知道这个简单问题的答案:“咖喱有什么意义?”我确实理解如何咖喱函数,只是不知道它背后的“为什么”

有人能给我解释一下咖喱函数的实际用途吗(除了每个函数只允许一个参数的语言之外,使用咖喱函数的必要性当然很明显。)


编辑:考虑到TLS中的一些示例,使用

(define (action kind)
    (lambda (a b)
        (kind a b)))
相对于

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

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

因此,您不必增加带有一点lambda的样板文件。

创建闭包非常容易。我时常使用SRFI-26。它真的很可爱。

一个有效使用curried函数的方法是减少代码量

考虑三个功能,其中两个几乎相同:

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

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

(define (action kind a b)
  (kind a b))
如果您的代码调用了
add
,它会依次调用
action
,使用kind
+
。与
mul
相同

您定义了这些函数,就像您在许多可用的命令式流行语言中所做的一样(其中一些已经包括了lambdas、curry和函数世界中常见的其他特性,因为所有这些都非常方便)

所有的
add
sum
do都在用相应的
种类
包装对
action
的调用。现在,考虑一下这些函数的定义:

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

(define mul-curried
  ((curry action) *))
它们变得相当短了。我们只是通过只传递一个参数,
kind
来实现函数
action
,得到了接受其余两个参数的curried函数

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

想象一下,函数
action
将立即被重写,以接受另外3个参数。如果不使用curry,您必须重写
add
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))

但是咖喱使你免于那个讨厌的、容易出错的工作;您甚至不必重写函数
addcurried
mul curried
中的符号,因为调用函数将提供传递给
action

的必要数量的参数,您可以将curried视为一种特殊化。选择一些默认值,给用户(可能是您自己)留下一个专门的、更具表现力的函数。

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

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

lengths' :: [[a]] -> [Int]
lengths' = map length
为什么要给一个不打算使用的变量命名

Curried函数在以下情况下也有帮助:

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

doubleAndSum' = map (sum . map (*2))
删除这些额外的变量可以使代码更容易阅读,并且您不需要在心里清楚地知道什么是xs,什么是ys


HTH.

我认为,如果您只能定义一元函数,则curry是处理一般n元函数的传统方法

例如,在lambda演算(函数式编程语言的起源)中,只有一个变量抽象(在FPLs中转换为一元函数)。关于lambda演算,我认为证明这种形式主义更容易,因为你实际上不需要处理n元函数的情况(因为你可以用一元函数来表示任意n元函数)


(其他人已经讨论了这个决定的一些实际影响,所以我就到此为止。)

咖喱本身就是一种语法上的糖分。语法糖就是你想让什么变得简单。例如,C希望使指令在汇编语言中变得“便宜”,如递增,简单,因此它们有用于递增的语法糖,即++符号

 t = x + y
 x = x + 1
替换为t=x+++y

函数式语言也可以很容易地包含这样的内容

f(x,y,z) = abc 
g(r,s)(z) = f(r,s,z). 
h(r)(s)(z) = f(r,s,z)
但它是全自动的。这允许由特定r0,s0(即特定值)绑定的g作为一个单变量函数传递

以perl的排序函数为例,该函数 排序子列表 其中sub是两个变量的函数,其计算结果为布尔和 列表是一个任意列表

您自然希望在Perl中使用比较运算符()并具有 sortordinal=sort() sortordinal在列表中工作。要做到这一点,您将被归类为一个咖喱函数。
事实上 在Perl中,列表的排序就是这样定义的

简言之:咖喱是一种糖,它能使一流的功能更加自然

使用
all::(a->Bool)->[a]->Bool
和一个curry谓词

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

Haskell中缀运算符可以在任意一侧使用,因此您可以轻松地在
elem
函数(是的元素)的指针或容器一侧使用。

我想为@Francesco answer添加示例


我们不能直接组合使用多个参数的函数。因为函数组合是函数编程的关键概念之一。通过使用Currying技术,我们可以组合包含多个参数的函数。

考虑到TLS中的一些示例和您上面的示例,
(定义(动作种类)(lambda(a b)(种类a b))
相对于
(定义(动作种类a b)(种类a b))
?我只能看到更多的代码,没有更多的灵活性…@Philip:除了味道和击键次数之外,没有任何好处:-)请看“。我不是说lambdas。。。如果我理解正确,第一个函数是curry,第二个不是。再说一次,如果我没有弄错的话,两者都做了完全相同的事情,但是咖喱版本在定义和调用时都更长-
((action*)5 5)
,而不是
(action*5)
@Philip: