web-dev-qa-db-ja.com

関数をパラメーターとして取る場合、関数はすぐに不純になりますか?

入力パラメーターの純度は実行時まで不明であるため、関数を入力パラメーターとして使用する場合、関数はすぐに不純と見なされますか?

関連:関数が関数の外部で定義されているが、パラメーターとして渡されていない純粋な関数を適用する場合、副作用がないという基準を満たし、出力が入力のみに依存する場合、それはまだ純粋ですか?

コンテキストについては、JavaScriptで関数型コードを記述しています。

17
Dancrumb

関数で使用されるすべての値がパラメータによってのみ定義されている限り、それは純粋な関数です。

同じ入力に対して毎回出力が同じになるファセットは、パラメーターが純粋であるかどうかによって制御されます。パラメータ(関数の引数のような)も純粋であると仮定すると、それは純粋です。

純粋性が強制されないJavascriptのような言語では、これは、パラメーターとして渡された不純な関数を呼び出すことによって、そうでなければ純粋な関数に不純な動作を持たせることが可能であることを意味します。

これは事実上、純粋性(つまり、ほとんどすべて)を強制しない言語の場合、引数として渡される関数を呼び出す純粋な関数を定義することは不可能であることを意味します。可能な限り純粋にそれらを記述し、それらを純粋な関数として推論することは依然として有用ですが、間違った引数を渡すと、純粋であるという前提が破られるため、注意が必要です。

実際の私の経験では、これは通常大したことではありません-純粋な関数の関数引数として不純な関数を使用することはまれです。

22
Daenyth

入力パラメーターの純度は実行時まで不明であるため、関数を入力パラメーターとして使用する場合、関数は直ちに不純と見なされますか?

いいえ。反例:

_function pure(other_function) {
    return 1;
}
_

_other_function_が純粋な関数であるか、純粋でない関数であるか、関数であるかは関係ありません。 pure関数は純粋です。

その他の反例:

_function identity(x) {
    return x;
}
_

xが不純な関数であっても、この関数は純粋です。 identity(impure_function)は、何度呼び出しても、常に_impure_function_を返します。 identity(impure_function)()が常に同じものを返すかどうかは関係ありません。関数の戻り値の戻り値は、その純度には影響しません。


一般に、関数が引数として渡された関数を呼び出す可能性がある場合、それは純粋ではありません。たとえば、関数function call(f) {f();}は純粋ではありません。これは、グローバルな状態や変更可能な状態について言及していなくても、falertのように見える可能性があるためです副作用。

関数が関数を引数として取るが、それらを呼び出さないか、それらを呼び出さない場合は、純粋である可能性があります。それが他の不純なことをするなら、それはまだ不純かもしれません。たとえば、function f(ignored_function) {alert('This isn't pure.');}は_ignored_function_を呼び出すことはありませんが、不純です。

入力パラメーターの純度は実行時まで不明であるため、関数を入力パラメーターとして使用する場合、関数はすぐに不純と見なされますか?

技術的には、はい。ただし、入力関数も純粋であることを保証する方法が言語にない限り。

関数が関数の外部で定義されているが、パラメーターとして渡されていない純粋な関数を適用する場合、副作用がなく、出力が入力のみに依存するという基準を満たしている場合でも純粋ですか?

はい。ここで重要なことに焦点を当てましょう。関数を純粋に呼び出すかどうかは、それ自体は役に立ちません。純粋な関数は便利です。どの入力に対しても同じ出力を生成し、状態や副作用に依存しないのは、非常に便利なプロパティのセットだからです。つまり、関数が実行されると、その入力に対する答えを「記憶」することができ、常に真になります。また、副作用を生成するために関数を再度実行する必要もありません。 And他の関数と並行して(または順不同で)その関数を実行し、動作が悪い隠れた相互作用がないことを確認できます。

これらの便利なプロパティは、関数が他の純粋な読み取り専用関数を使用して、その参照方法に関係なく機能する場合でも保持されます。

12
Telastyn

Telastynが言ったように:技術的には、入力言語も純粋であることを保証する方法が言語にない限り、そうです

これは仮説ではありません。これを保証するための確かな良い方法があります。少なくとも強く型付けされた言語では。

あなたがJavaScriptで書くような純粋な〜関数

_function foo(f) {
   return f(1) + 2;
}
_

haskellに直接翻訳できます。

_foo :: (Int -> Int) -> Int
foo f = f 1 + 2
_

これで、JavaScriptで次のような悪事を行うことができます

_js> foo (function(x) {console.log("muharhar"); return 0})
muharhar
2
_

これはHaskellでは不可能です。その理由は、console.log()のような副作用のあるものは、somethingだけではなく、常に_IO something_の結果型を持たなければならないためです。

_GHCi> foo (\x -> print "muarhar" >> return 0)

<interactive>:7:12:
    Couldn't match expected type ‘Int’ with actual type ‘IO b0’
    In the expression: print "muarhar" >> return 0
    In the first argument of ‘foo’, namely
      ‘(\ x -> print "muarhar" >> return 0)’
    In the expression: foo (\ x -> print "muarhar" >> return 0)
_

この式でタイプチェックを行うには、fooに型シグネチャを与える必要があります

_foo :: (Int -> IO Int) -> Int
_

しかし、それではもう実装できないことが判明しました。引数関数の結果にはIOがあるため、foo内では使用できません。

_<interactive>:8:44:
    Couldn't match expected type ‘Int’ with actual type ‘IO Int’
    In the first argument of ‘(+)’, namely ‘f 1’
    In the expression: f 1 + 2
_

IOfooアクションを使用できる唯一の方法は、fooの結果の型が_IO Int_自体である場合です。

_foo :: (Int -> IO Int) -> IO Int
foo f = do
   f1 <- f 1
   return (f1 + 2)
_

しかし、この時点では、fooのシグネチャからも、それが純粋な関数ではないことは明らかです。

5
leftaroundabout

いいえそうではありません。

渡された関数が不純であり、関数が渡された関数を呼び出す場合、関数は不純であると見なされます。

純粋/不純な関係は、JSの同期/非同期に少し似ています。純粋でないコードを自由に使用できますが、その逆はできません。

0
Bobby Marinoff