1

所以,我只是在想链接有多酷,以及它如何让事情更容易阅读。对于许多语言,当将一堆函数应用于变量时,您会编写如下内容:

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
4

8 回答 8

5

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

你这样写:x |> f |> g |> h |> i

查看这篇博客文章,它可以很好地了解现实生活中的使用情况。

于 2010-11-26T02:13:13.057 回答
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

于 2010-11-26T03:35:39.183 回答
3

它不是函数式编程独有的,尽管它可能最好用函数式语言实现,因为函数组合的整个概念完全属于函数式编程的领域。

一方面,任何具有面向对象倾向的语言都具有返回类实例的方法的链接:

obj.method1().method2().method3(); // JavaScript
MyClass->new()->f()->g()->i(); # Perl

或者,这种链接模式最著名但最不“编程语言”的示例将是完全非 OO 和非功能性的……你猜对了,Unix 中的管道。如中,ls | cut -c1-4 | sort -n。由于 shell 编程被认为是一种语言,我说它是一个完全有效的例子。

于 2010-11-26T02:11:36.030 回答
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 非常广泛地使用它。

于 2010-11-26T21:58:36.217 回答
2

哈斯克尔。以下三个例子是等价的:

  • 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)

于 2010-11-26T02:14:51.223 回答
2

您所描述的本质上是 Fluent Interface 模式。

维基百科有很多语言的一个很好的例子:

http://en.wikipedia.org/wiki/Fluent_interface

Martin Fowler 在这里写了他的文章:

http://www.martinfowler.com/bliki/FluentInterface.html

正如 DVK 指出的那样 - 方法可以返回其所属类的实例的任何 OO 语言都可以提供此功能。

于 2010-11-26T02:16:10.287 回答
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 中的内置运算符,而是$。我已经掩盖了中缀位。如果您很好奇,那是使上述代码解析为的技术性问题:

(((x % f) % g) % h) % i -- intended

并不是:

x % (f % (g % (h % i))) -- parse error (which then leads to type error)
于 2010-12-02T21:48:31.953 回答
1

如果您通常不做一些数学运算,我并不是建议您可以使用Mathematica ,但它肯定足够灵活,可以支持 Postfix 表示法。事实上,您可以定义自己的符号,但为了简单起见,让我们继续使用 Postfix。

您可以输入:

Postfix[Sin[x]]

要得到

x // Sin  

转换为后缀表示法。或者,如果您有更深层次的表达:

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

顺便说一句:作为我的魔法语言在哪里的答案,?,看到这个:

(x//Sin 
  // Cos
  // Exp 
  // Myfunct)  

Myfunct[E^Cos[Sin[x]]]  

PS:作为对读者的练习:) ...如何为需要 n vars 的函数执行此操作?

于 2010-11-26T15:47:24.380 回答