currying会产生部分应用的功能吗?

时间:2012-06-03 12:04:53

标签: haskell f# functional-programming

curry函数的结果是部分应用函数吗?我理解currying是如何工作的,虽然我理解了部分函数应用程序是如何工作的,但我不清楚这些概念是否存在一些交叉。

我的混淆来自Learn you a Haskell for great good的以下引用,这与我先前对基于this blog post by John Skeet的概念的理解相冲突。

  

简单来说,如果我们调用参数太少的函数,我们就会得到   返回一个部分应用的函数,意味着一个函数   我们遗漏了许多参数。

举一个例子(在F#中虽然问题是关于函数式编程)

> let add a b = a + b;;

val add : int -> int -> int

> let inc = add 1;;

val inc : (int -> int)

在这个例子中是inc部分应用的函数吗?

2 个答案:

答案 0 :(得分:3)

一般来说, currying 意味着将一个双参数函数转换为一个接受一个参数并返回另一个单参数函数的函数,以便用第一个参数调用curried函数的结果然后第二个参数的结果相当于用两个参数调用原始(uncurried)函数。在具有闭包和动态类型(或类型推断)的伪C语言中,这看起来像这样:

// The original, uncurried function:
function f(a, b) { return 2 * a - b; }

// The curried function:
function g(a) {
    return function(b) {
        return f(a, b);
    }
}

// Now we can either call f directly:
printf("%i\n", f(23, 42));

// Or we can call the curried function g with one parameter, and then call the result
// with another:
printf("%i\n", (g(23))(42));

通过多次currying,我们可以将任何多参数函数减少为嵌套的单参数函数集。

在Haskell中,所有函数都是单参数;像f a b c这样的构造实际上等同于我们虚构的C-with-closures中的((f(a))(b))(c)。将多个参数真正传递给函数的唯一方法是通过元组,例如f (a, b, c) - 但由于curried函数的语法更简单,并且语义更灵活,因此很少使用此选项。

Haskell Prelude定义了两个函数curryuncurry来在这两个表示之间进行转换:curry属于((a,b) -> c) -> a -> b -> c类型,即它需要一个 - 参数函数接受元组(a, b)并返回c,并将其转换为类型为a -> b -> c的函数,该函数接受a并返回函数需要b并返回cuncurry正好相反。

部分申请不是真的;它只是给你一个curried函数的情况的名称(例如f a b),而不是完全展开整个链(例如,f 23 42),你停在路上的某个地方,然后通过进一步产生的功能,例如let g = f 23。为了部分应用一个函数,它必须是curry(你不能部分地将f (a, b)应用为let g = f (a)),但由于以curry方式编写函数是Haskell中的默认函数,因此部分应用程序很容易并且常见的做法。

答案 1 :(得分:0)

简答:inc是通过部分申请获得的功能。

curried函数的结果是目标语言中某种类型的值(Haskell,F#或其他),所以它可能是一个函数(但它也可能是一个整数,一个布尔值,......,取决于在你的声明上。)

关于部分应用程序......它只是一个返回其他函数的函数应用程序的名称,但从技术上讲它是一个像其他函数一样的函数应用程序。您返回的函数基于先前的参数甚至不是强制性的。以\x -> id为例:您总是获得身份函数,与输入x无关。