非折叠方法引用及其他

发布者    |       Ceylon

像这样的方法引用Float.times在Ceylon中表示为折叠形式。我可以写

Float twoTimes(Float x) = 2.times;

这里,表达式2.times是方法times()对接收器表达式2.

的部分应用产生的典型一等函数引用

Float times(Float x)(Float y) = Float.times;

但实际上,表达式Float.times是方法声明的一个元模型引用。类型Method<Float,Float,Float>Callable<Callable<Float,Float>,Float>的子类型,因此我们可以将其视为函数引用。

因此,twoTimes()的另一个定义是

Float twoTimes(Float x) = Float.times(2);

(我们通过提供其两个参数列表中的一个来部分应用)Float.times不幸的是,以下代码没有正确类型

问题在于

Float product(Float x, Float y) = Float.times;  //error: Float.times not a Callable<Float,Float,Float>

,当作为一个函数引用来考虑时,它是一个接受Float.timesFloat并返回接受的函数的高阶函数并返回接受而不是接受两个并返回接受s 的一阶函数。

那么我们如何将方法引用Float.times转换为只有一个参数列表的非折叠函数呢?

好吧,一个真正简单的方法就是回退到编写

Float product(Float x, Float y) {
    return x.times(y);   //or even: x*y
}

但是,嗯,这篇文章的目的是展示Ceylon中高阶函数的一些高级特性,所以这不是一个非常有趣的解决方案。相反,我们将使用一个真正酷的高阶函数,它将成为Ceylon语言模块的一部分。这只需要两行代码,所以我相信你马上就能理解它

R uncurry<R,T,P...>(R curried(T t)(P... p))(T receiver, P... args) { 
    return curried(receiver)(args);
}

哇!Wtf?

显然,你需要重新阅读第8部分!好吧,已经读完了吗?酷,现在让我们来展开这个

  1. 首先,它是一个具有两个参数列表的函数,所以uncurry()()是一个返回函数的函数。
  2. 第一个参数列表包含一个具有两个参数列表的单个参数,所以参数curried()()也是一个返回函数的函数。
  3. curried()()具有以下形式的参数:P...,是一个 有序类型参数,因此我们知道curried()()是针对具有任意参数列表的函数进行某种抽象。
  4. 第二个参数列表包含两个参数,与curried()()的参数列表中的单个参数的类型相同。这些是uncurry()().

返回的函数的参数。 uncurry()()执行的操作是接受一个以柯里化形式存在的函数,其中第二个参数列表可以有任意数量的参数,并生成一个只有一个参数列表的函数,包括参数函数的所有原始参数。这是curried()()

Float product(Float x, Float y) = uncurry(Float.times);

的参数列表“扁平化”为单个参数列表。因此,我们可以编写以下内容:

R curry<R,T,P...>(R uncurried(T t, P... p))(T receiver)(P... args) { 
    return uncurried(receiver,args);
}

以类似的方式表示函数的其他类型操作。考虑以下函数:uncurry()()此函数正好与

Float times(Float x)(Float y) = curry(product);
Float double(Float y) = times(2.0);

相反,它接受参数函数的第一个参数,并将其分离成自己的参数列表,允许参数函数部分应用

R compose<R,S,P...>(R f (S s), S g(P... p))(P... args) { 
    return f(g(args));
}

现在考虑以下函数:

Float incrementThenDouble(Float x) = compose(2.0.times,1.0.plus);

幸运的是,您不需要自己编写像curry()(), uncurry()()compose()()这样的函数。它们是作为语言模块的一部分打包的通用工具。尽管如此,了解像这样的机制可以在Ceylon的类型系统中表达出来是很不错的。


返回顶部