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

関数合成の概念全体が関数型プログラミングの領域にあるため、おそらく関数型言語で実装するのが最適ですが、これは関数型プログラミングに限定されるものではありません。

1 つには、オブジェクト指向に傾倒している言語には、クラスのインスタンスを返すメソッドの連鎖があります。

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

あるいは、この連鎖パターンの最も有名でありながら「プログラミング言語」の最も少ない例は、完全にオブジェクト指向ではなく、機能しないものです... ご想像のとおり、Unix のパイプです。のように、ls | cut -c1-4 | sort -n. シェル プログラミングは言語と見なされるため、これは完全に有効な例だと言えます。

于 2010-11-26T02:11:36.030 に答える
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 に答える
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

ハスケル。次の 3 つの例は同等です。

  • 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

そして、マーティン・ファウラーは彼の記事をここに書いています:

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

DVK が指摘するように、メソッドが属するクラスのインスタンスをメソッドが返すことができるオブジェクト指向言語は、この機能を提供できます。

于 2010-11-26T02:16:10.287 に答える
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

チッ!

ところで:私の魔法の言語はどこにあるの?、これを参照してください:

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

与える

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

PS: 読者への演習として :) ... n 変数を取る関数に対してこれを行う方法は?

于 2010-11-26T15:47:24.380 に答える
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 に答える