链接到极端的语言?

时间:2010-11-26 02:05:45

标签: language-agnostic fluent-interface method-chaining

所以,我只是在思考酷链是多么简单,以及它如何让事情变得更容易阅读。有很多语言,当将一堆函数应用于变量时,你会写这样的东西:

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

8 个答案:

答案 0 :(得分:5)

是的,使用F#,您有一个管道运算符|>(也称为正向管道运算符,并且您有一个向后管道<|)。

您可以这样写:x |> f |> g |> h |> i

选中此blog post,了解真实生活情况。

答案 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)