1

私はJのコンビネータをJavascriptで実装しようとしていました。Javascriptではなぜx => f(f)(x)をf(f)に置き換えることができないのですか?

私は次のことを実現するために管理:

const y0 = gen => (f => f(f))(f => gen(x => f(f)(x))); 
const factorial0 = y0(fact => n => n<=2 ? n : n * fact(n-1)); 
console.log(factorial0(5)); 
// 120 

それはうまく動作します。

次に、私は式x => f(f)(x)を考えていました。

私の理解では、式x => g(x)gに相当します。 yx => g(x)に適用すると、g(y)となり、ygに適用すると、g(y)と評価されます。

x => f(f)(x)f(f)に置き換えました。

const y = gen => (f => f(f))(f => gen(f(f))); 
const factorial = y(fact => n => n<=2 ? n : n * fact(n-1)); 
console.log(factorial(5)); 
// RangeError: Maximum call stack size exceeded 

しかし、このバージョンはスタックオーバーフローでクラッシュします。

したがって、x => f(f)(x)f(f)の違いは、1つが動作し、もう1つがクラッシュするためです。

x => f(f)(x) 

+1

厳しい評価のため、 – Bergi

+1

@Bergi 3つの言葉 - 私はこれを怠惰な説明と呼びます:D – ftor

答えて

2

私が考えていることは、それらの2つの表現がまったく同じではないということです。一方x => f(f)(x)

は - これは文字通りの新しい関数を作成します(それがすぐに起動されません - この関数が呼び出されたときにのみ起動されます)。一方f(f)

- JavaScriptでこれはANはあります式はf関数を呼び出します。その結果、スタックオーバーフローが発生します。

+1

つまり、 'x => f(f)(x)'は 'f(f)'の遅延バージョンです。 Javascriptは厳密に評価されるので、無限再帰を避けるために 'f(f)'のようなパターンをラムダにラップする必要があります。 – ftor

+0

これは問題の要点だと思います。式x => f(f)(x)は、xが提供されるまでf(f)の評価を遅らせる。 –

4

さて、1つのパラメータ、xを取る関数です。関数が呼び出されると、関数fが呼び出され、fへの参照がパラメータとして渡されます。関数fは別の関数を返し、呼び出され、xがパラメータとして渡されます。古い学校の構文で

、それだけでf(f)それ自体では大きく異なるのです

function(x) { 
    return f(f)(x); 
} 

です。これは関数 "f"の呼び出しであり、 "f"はパラメータとして渡されます。

したがって、x => f(f)(x)f(f)の式ですが、それらは大きく異なるセマンティクスを表します。最初の値は関数への参照です。表現自体は特に何もしません —特に、関数f()は呼び出されません。 f(f)の値は、f()という関数が何であっても、式を実行する—と呼び出されたときに返される関数f()になります。

関連する問題