関数をパラメーターとして使用する場合、関数はすぐに不純ですか?


17

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

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

コンテキストについては、JavaScriptで機能コードを作成しています。


些細なカウンター例として、考える:foo = function(function bar){ print(bar.toString()) }
デビッド復活モニカ言う

1
@DavidGrinbergこれは反例ではなく、実際に大きな問題を浮き彫りにしていると思います。オーバーライドできる関数があり、実装に副作用がないことを保証できない場合、オブジェクトを取得してメソッドを呼び出すほとんどの関数が純粋であることも保証できません。たぶんバーのtoString()はディスクからいくつかのファイルを削除しますか?
ジョシュアテイラー

3
@DavidGrinbergしかし、私はあなたが良い方向に考えていると思います。 foo = function(function bar) { return 3; } 純粋であり、引数として関数を取ります。
ジョシュアテイラー

@ジョシュアテイラーフェアポイント、私はそれを考えていませんでした。しかし、あなたはすでに本質的に問題を解決しました。別の解決策として、「ルート」toString()(つまり、Javaのオブジェクトにあるもの)を呼び出すだけです。
デビッドは、モニカを復活させる

回答:


22

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

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

Javascriptのような純度が強制されていない言語では、これは、パラメーターとして渡された不純な関数を呼び出すことで、純粋な関数に不純な振る舞いをさせることができることを意味します。

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

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


「関数で使用されるすべての値がそのパラメーターによってのみ定義されている限り、それは純粋な関数です」というステートメントについて。定数の場合はどうなりますか?関数を持っている場合areaOfCircle r => Math.Pi * r * rareaOfCircleパラメータを使用しないので純粋ではありませんか?
デビッドアルノ

2
@DavidArnoそれは公正な点です。参照の透過性によると、静的な外部値を参照することは、ハードコーディングされていることと変わらないため、それでも純粋です。
デニス

1
「これは、純粋な関数に不純な動作をさせることができることを意味します」-定義により、純粋な関数に不純な動作を持たせることはできません。f(f2)呼び出す関数がf2依存するものに推移的に依存しないと考えるのは間違いですf2。任意の渡された関数を呼び出す可能性のある関数は純粋ではありません。
user2357112は、Monicaを

2
@Daenyth:良いですが、関数は渡された関数を呼び出さなければならないと仮定しています。function compose(f, g) {return function h(x) {return f(g(x));};}関数を引数としてとっても純粋なのようなものかもしれません。
user2357112は

1
「純粋な関数の関数引数として不純な関数を使用することはめったにありません。」-関数型言語ではありませんが、特定のC ++ライブラリ関数には、述語引数が(ある程度近似した)純粋でなければならないという特定の警告があります。そのため、ある意味では、これはまれであるだけでなく、決して有効ではないことを意味します。しかし、別の意味では、彼らがそれを禁止しなければならないという事実は、人々が時々それをしたいからです。たとえばfind、遭遇する3番目の一致項目、またはそのようなナンセンスに対して「true」を返す不純な述語をルーチンに渡したいとします。
スティーブジェソップ

19

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

いいえ。反例:

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();}は純粋ではありません。なぜなら、グローバルな状態や可変状態について言及していないにもかかわらず、目に見える副作用を引き起こすfようなものかもしれないからですalert

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


4
この反応は非常に慢に思えます。懸念は、呼び出される関数パラメーターに関するものであるという質問から推測できます。他の関数を呼び出さずにパラメーターとしてとることができる/行う関数の存在は、この質問に影響しません。
ウォルペン

13
@walpen:質問では、引数の呼び出しについて言及していません。関数を呼び出すことなく、関数が入力として別の関数を使用する可能性があることを質問者が認識していると想定する理由はありません。あなたがそれらを仮定するつもりであると単に仮定するのではなく、このような隠された仮定を指摘することが重要です。
user2357112は

12

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

技術的には、入力関数も純粋であることを保証する方法が言語にある場合を除き、はい。

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

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

関数が他の純粋な読み取り専用関数を使用して作業を行う場合、それらの参照方法に関係なく、これらの有用なプロパティは保持されます。


5

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

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

JavaScriptで次のように記述するようなpure〜関数

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()があるようなものは、単独IO somethingではなく、常に結果タイプを持たなければならないから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

IOアクションを使用できる唯一の方法fooは、の結果にfooIO Int自体がある場合です:

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

しかし、この時点で、署名から、fooそれが純粋な関数でもないことは明らかです。


1
「不可能」と言う前に、以下をunsafeIOご覧ください:
ベルギ

2
@Bergi:それは実際にはHaskellの一部ではなく、その外部関数インターフェースです:他の言語で定義された関数が純粋であると断言できるようにするため、他の言語には一般に型シグネチャから推測できないためなどのことIO。ちなみに、「純粋な」関数の副作用を隠して騒乱を引き起こすために使用することもできますが、純粋な関数の評価順序を指定する信頼性の高い方法がないため、Haskellでは本当に安全ではありません。
15年

ええ、それは本当です。しかし、以前はアプローチの安全性を確立する必要があった「純粋な」機能で有益な副作用を「隠す」ために使用されているのを見たと思います。
ベルギ

@Bergiほとんどの場合、使用すべきではありませんunsafeIO。これは、型システムが保証する最後の手段であるエスケープハッチです。したがって、それは良い点ではありません。
アンドレスF.

0

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

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

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


この回答では、この説明でまだ説明されていないものは追加されません...事を繰り返す前に、以前の回答を確認してください:)
Andres F.

同期/非同期アナロジーはどうですか?
ボビーマリノフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.