所以,我只是在思考酷链是多么简单,以及它如何让事情变得更容易阅读。有很多语言,当将一堆函数应用于变量时,你会写这样的东西:
i(h(g(f(x))))
你必须从右到左或从最里面到最外面阅读它。您首先应用f
,然后应用g
,依此类推。但如果它被链接,它看起来更像是
x|f|g|h|i
你可以像普通人一样阅读它。所以,我的问题是,必须有一些语言可以这样做,它们是什么?这就是这些功能性编程语言的用途吗?
因此,我通常最终会创建一大堆临时变量,这样我就可以将它分成不同的行并使其更具可读性:
a = f(x)
b = g(a)
c = h(b)
what_i_really_wanted_all_along = i(c)
在我的魔法语言中,你可以将它分成不同的行,如果它们变得太长,而不需要插入变量:
x | f
| g
| h
| i
答案 0 :(得分:5)
答案 1 :(得分:3)
它并不是函数式编程所独有的,尽管它最好用函数式语言实现,因为函数组合的整个概念完全在函数式编程领域。
首先,任何具有面向对象弯曲的语言都会链接返回类实例的方法:
obj.method1().method2().method3(); // JavaScript
MyClass->new()->f()->g()->i(); # Perl
或者,这个链接模式中最着名但最不“编程语言”的例子将是完全非OO和非功能性的东西......你猜对了,管道在Unix中。如同,ls | cut -c1-4 | sort -n
。由于shell编程被认为是一种语言,我说这是一个非常有效的例子。
答案 2 :(得分:3)
嗯,你可以在JavaScript及其亲戚中这样做:
function compose()
{
var funcs = Array.prototype.slice.call(arguments);
return function(x)
{
var i = 0, len = funcs.length;
while(i < len)
{
x = funcs[i].call(null, x);
++i;
}
return x;
}
}
function doubleIt(x) { print('Doubling...'); return x * 2; }
function addTwo(x) { print('Adding 2...'); return x + 2; }
function tripleIt(x) { print('Tripling...'); return x * 3; }
var theAnswer = compose(doubleIt, addTwo, tripleIt)( 6 );
print( 'The answer is: ' + theAnswer );
// Prints:
// Doubling...
// Adding 2...
// Tripling...
// The answer is: 42
如您所见,这些函数从左向右读取,对象和函数都不需要任何特殊实现。秘密全部在compose
。
答案 3 :(得分:2)
Haskell中。以下三个例子是等效的:
i(h(g(f(x))))
(嵌套函数调用)x & f & g & h & i
(按要求从左到右链接)(i . h . g . f)(x)
(函数组合,在Haskell中更常见)http://www.haskell.org/haskellwiki/Function_composition
http://en.wikipedia.org/wiki/Function_composition_(computer_science)
答案 4 :(得分:2)
您所描述的基本上是Fluent Interface模式。
维基百科有很多语言的好例子:
http://en.wikipedia.org/wiki/Fluent_interface
Martin Fowler在这里写道:
http://www.martinfowler.com/bliki/FluentInterface.html
正如DVK指出的那样 - 任何一种方法可以返回它所属类的实例的OO语言都可以提供这种功能。
答案 5 :(得分:2)
C#扩展方法可以完成一些非常接近你的魔法语言的东西,如果不那么简洁:
x.f()
.g()
.h()
.i();
声明方法的地方:
static class Extensions
{
static T f<T>(this T x) { return x; }
static T g<T>(this T x) { return x; }
...
}
Linq非常广泛地使用它。
答案 6 :(得分:1)
如果你不经常做一些数学计算,我建议你不要使用Mathematica,但它肯定足够灵活,可以支持Postfix表示法。实际上,您可以定义自己的符号,但为了简单起见,让我们继续使用Postfix。
您可以输入:
Postfix[Sin[x]]
获得
x // Sin
转换为Postfix表示法。或者如果你有更深刻的表达:
MapAll[Postfix, Cos[Sin[x]]]
获得:
(Postfix[x]//Sin)//Cos
首先你可以看到Postfix [x],Mathematica x是一个稍后要评估的表达式。
相反,您可以输入:
x // Sin // Cos
当然要
Cos[Sin[x]]
或者您可以使用非常频繁使用的习惯用法,使用Postfix形式的Postfix:
Cos[x] // Postfix
获得
x // Cos
HTH!
顺便说一句: 作为使用我的魔法语言的地方的答案,,请参阅:
(x//Sin
// Cos
// Exp
// Myfunct)
给出
Myfunct[E^Cos[Sin[x]]]
PS:作为读者的练习:) ...如何为需要n个变量的函数执行此操作?
答案 7 :(得分:1)
如前所述,Haskell支持函数组合,如下所示:
(i . h . g . f) x
,相当于:i(h(g(f(x))))
这是数学中函数组合的标准操作顺序。然而,有些人仍然认为这是落后的。在没有过多讨论哪种方法更好的问题上,我想指出您可以轻松定义翻转合成运算符:
infixr 1 >>>, <<<
(<<<) = (.) -- regular function composition
(>>>) = flip (.) -- flipped function composition
(f >>> g >>> h >>> i) x
-- or --
(i <<< h <<< g <<< f) x
这是标准库Control.Category使用的符号。 (虽然实际的类型签名是一般化的,但除了函数之外还可以用于其他事情)。如果您仍然对最后的参数感到困扰,您还可以使用函数应用程序运算符的变体:
infixr 0 $
infixl 0 #
f $ x = f x -- regular function application
(%) = flip ($) -- flipped function application
i $ h $ g $ f $ x
-- or --
x % f % g % h % i
哪个接近您想要的语法。据我所知,%
不是Haskell中的内置运算符,但$
是。{1}}。我掩盖了中缀位。如果你很好奇,这就是使上述代码解析为:
(((x % f) % g) % h) % i -- intended
而不是:
x % (f % (g % (h % i))) -- parse error (which then leads to type error)