Today()が不純な関数の例なのはなぜですか?


38

「純粋関数」に関するこのウィキペディアの記事のようなものを読むToday()と、不純関数の例としてリストされているように見えますが、私にはかなり純粋に見えます。正式な入力引数がないためですか?実際の時刻が「関数への入力」として扱われないのはなぜですか。その場合、同じ入力を与えた場合、つまりtoday()同時に2回実行した場合、または時間をさかのぼって再度実行した場合(仮定: ))、出力は同じ時間になります。Today()あなたに乱数を与えることはありません。常に時刻が表示されます。

ウィキペディアの記事には「異なる時間で異なる結果が得られる」と書かれていますが、それは異なるx sin(x)ことを言うと異なる比率が得られるようなものです。そしてsin(x)、純粋な関数の例です。


8
時刻に合格した場合、関数は何をしますか?
JBキング

1
時刻がわかると思います。(最も便利な機能ではありません)。しかし、これには議論の余地はありません。これが答えの根本だと思います。
ブラッド

3
(指定した入力パラメーターに基づいて)出力を予測できますか?
ダニエルB

1
@DanielB存在しない/ null入力パラメーターに予測力はありません。私にできることは、私の腕時計(jk my cell phone)を見ることだけです。
ブラッド

「なぜ実際の時刻が「関数への入力」として扱われないのか」これは、基本的にモナドが解決しようとする問題です。純粋な関数は入力に基づいているだけで、副作用はありません。「私の前の世界の状態」を入力にし、「私の後の世界の状態」を戻り値の一部にし、これらの世界の状態をプログラムに渡すと、再び純粋になります。
ショーンマクサムシング

回答:


103

正式な入力引数がないためですか?

これは、出力が入力ではない何か、つまり現在時刻に依存しているためです。

実際の時刻が「関数への入力」として扱われないのはなぜですか

パラメータとして渡さなかったからです。パラメータとして渡した場合、関数は日付の恒等関数になりますが、これはほとんど役に立ちません。Today()関数の全体のポイントは、外部の絶えず変化する値(時間)に依存する何かを出力することです。

純粋関数の利点は、その振る舞いが完全に再現可能かつ決定論的であり、形式的な証明と厳密な保証が容易になることです。彼らはいつも同じことをします。Today()これはほとんど正反対です。常に(時間の細分性を考慮して)異なることを行います。


2
したがって、現実の時間は一種の入力ですが、それは入力として与えられておらず、関数の制御外(関数の内部と呼び出している人の制御外の両方Today()Today()が不純になるためです。このToday()関数は少し馬鹿げた例かもしれません。より適切なのはCount()機能です。カウントCount()するアイテムの数が同じであれば、常に同じ数が返されますが、Count()それは範囲外であるため不純です。
ブラッド

1
@bradはやや灰色の領域です-暗黙の実引数-配列またはリストがあります。不変のリストと同じ引数を指定すると、常に同じ値が返されます。
マックス

34
「現実の時間は一種の入力です」-はい。実際、グローバル状態はすべての関数で暗黙的に利用可能です(つまり、「入力の並べ替え」)が、結果依存している場合は不純です!
AakashM

4
count()ほとんどのプログラミング言語の@Brad は間違いなく純粋です。明示的な入力値(カウントが必要なコレクション)があります。myCollection.count(); などの構文と混同しないでください。それはただの砂糖ですcount(myCollection)
アンドレスF.

いつものように素晴らしい答えですが、不変の自由変数を明示的にカバーしていません。それらは関数への入力ではなく、パラメータとして渡されませんが、参照的に透過的であっても関数はそれらに依存します。

24

sin(x)同じxままである限り、常に同じ値を返します。あなたのコントロールの外の値Today()依存するので、時間とともに異なる結果を返すかもしれません。たとえば、プログラムの実行$current_datetime にプログラムの制御を超えた何かがシステムの内部変更するToday()と、突然異なる結果が生じます。


「常に異なる値を返す」というのは少し... 不純な表現です。ウィキペディアによると、「現在の曜日を返す」ということは、月曜日に取得した値が変わらないことを意味します
-gnat

7
@gnat:確かに、プログラムの外部の何かがコンピューターの内部カレンダーを変更して、突然木曜日だと思った場合を除きます。その後、呼び出しToday()は月曜日に「木曜日」を返します。
FrustratedWithFormsDesigner

3
@gnatまあ、それは常に異なる値を返すとは限りません(そうする便利な関数はほとんどありません)。しかし、ほとんどの不純な関数と同様に、戻り値は単一のプログラムの実行中でも変化する可能性があります(夜間に実行される場合など)。

3
@delnan:はい、それは素朴なデータベーススクリプト作成者の悩みの種です!:P「しかし、300個のレコードを見逃す可能性はありますか?昨日の朝テストしたときに、スクリプトは正常に機能しました!」
FrustratedWithFormsDesigner

@delnanそれは確かです。私は、最初の文言で常に使用すること(現在のバージョンの回答で修正可能)が多少不正確であることを指摘しただけです
-gnat

13

Today()は不純な関数です。その結果は、ユーザーが与えないものに依存しているためです。具体的には、現在のシステム時刻。したがって、呼び出しで提供された入力のみに基づく場合、その結果は決定的ではありません。

純粋な関数はになりますint Add(int a, int b) {return a + b;}。この関数は与えられたものだけで機能し、他の外部状態データは使用しません。これの自然な結果は、あなたがAdd(2,2)今から時間の終わりまで4を得ることができるということです。さらに、関数は外部状態を変更しないため(「副作用」はありません)、現在から2と2を時間の終わりまで追加()しても、システム内の他の部分は変更されません。関数の結果を変数に代入するか、値を使用して状態を更新します(関数自体が実行する操作ではありません)。事実上、古典的な数学演算はすべて純粋な関数であり、そのように実装できます。

今日は()、一方、よい行に2回呼び出されたときに同じ値を生成するが、数日間繰り返し呼び出されていない場合。これは、関数のパラメーターとして提供されていない外部状態データに依存しているためです。その結果、プログラムの境界内では、Today()関数の結果を制御することは不可能です。特定の日に特定の値を生成し、それが実行されているコンピューターのシステムクロックを変更しない限り、他の日にその値を生成することはありません(通常、プログラムの境界外で変更が発生します)。

不純な機能は必ずしも悪いことではありません。データストア、通信パイプライン、UIディスプレイ、周辺機器など、プログラムの境界の外側にあるものと対話するには、関数型言語であっても不純な機能が必要です。これらのことを何もしないプログラムはプログラムですその有用性は大幅に制限されています。入力を受け入れる手段や出力を通知する手段がないため、何もしないこともあるため、このようなプログラムを些細なものまで呼び出すことさえあります。関数型言語で記述されたプログラムは、ランタイムによって提供される入力のみを持ち、明示的に定義された不純なメソッドなしでランタイムにレポートされる出力を生成できますが、それはランタイムが不完全なコンピューターシステム内でのこれらの不純な詳細をすべて抽象化するためです

使用している関数のどれが純粋であり、どの関数がそうでないかを知ることは、とても良いことです。不純な機能は、物事を行うか、その使用法から明らかでない物事に依存しているため、使用法の知識のみが与えられた場合、予測できない動作をする可能性があります。それを使用するシステムを一貫性のある状態にし、決定論的な結果を期待するためには、関数の目的、したがって外部状態から必要なこと、または外部状態に対して行うことについてのさらなる知識が必要です。


8

この関数がそのページの冒頭で与えられた純度の最初のテストに失敗することはかなり明白なようです:

  1. この関数は、同じ引数値が与えられた場合、常に同じ結果値を評価します。関数の結果値は、プログラムの実行が進むにつれて、またはプログラムの異なる実行間で変化する可能性のある隠された情報や状態に依存することも、I / Oデバイスからの外部入力に依存することもできません。

引数を受け取らないため、引数値の可能なセットは1つだけであることに注意してください-空のセット。そして、この関数は同じ「引数値」に対して異なる結果を返すことができ、実際に返します。

さらに、関数の結果の値、「プログラムの実行が進むにつれて変化する可能性がある非表示...状態」に依存します。別の失敗。


@JörgWMittag引数のない関数が値を返せないことをどこで主張するのかわかりません。
AakashM

脳のおなら。「戻り値の可能なセットは1つだけです」と読みました。
ヨルグWミットタグ

8

() => 1常に1を返すため、純粋な関数になります。Today()「月曜日」または「火曜日」、または他のほとんどの値を返す場合があります。

それを考える別の方法は、純粋な関数は状態に依存しないということです。世界は通常、状態と見なされます。今日が何曜日であるかを知るには、現実の状態を知る必要があります。

ただし、世界の状態について特別なことを知る必要はありませんsin(x)。またsin(x)、指定xされたに対する呼び出しは、同じ値を返します。


ウィキペディアは、「現在の曜日を返します」それは月曜日を返すことができることを意味し、火曜日などではなく、「2013年1月23日」も「2013年1月24日」と言う
ブヨ

7
@gnat:更新されましたが、違いはそれほど重要ではありませんでした。
グヴァンテ

2

Date(timestamp)純粋な関数になります。そのべき等性のため。そして、副作用がないからです。

Today()いつ呼び出すかによって結果が異なります。それが不純です。それはi等ではありません。ただし、副作用はありませんが、それによって純粋になるわけではありません。


2

純粋な関数を議論するときに私が考える小さな擬似コードは次のとおりです

newValue = Function();
while(true)
{
   oldValue = newValue;
   newValue = Function();
   assert( newValue == oldValue );
}

それが無期限に実行され、アサートがトリガーされない場合、それは純粋な関数です。さらに、引数を使用する関数がある場合は、少し変更してください...

oldValue = Function( importantVariableToYourApp );
newValue = Function( importantVariableToYourApp );
assert( newValue == oldValue );

アプリで変数を割り当てるたびにそれを使用でき、アプリの結果が変わらず、アサートに失敗しない場合、それは純粋な関数です。


2

まず、引数のない関数(またはインデックスのない配列やキーのないマップ)はありません。1つ以上の引数値を別の値にマッピングするのは、関数の定義特性です。

したがって、todayはまったく関数ではないため、純粋な関数ではありません。または、構文を解釈する場合があります

today()

それが意味するように少し

today   ()      -- today, applied to the value ()

たとえば、Haskellでは、これは有効です。

data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving Show
today :: () -> Day
today () = ....?
main = print (today())

単一の値()を持つタイプ()があるためです。

問題は、today()だけがある場合、曜日をどのように計算できるかだけです。システムタイマーを読み取ることなく、直接またはヘルパー不純関数を介して実行することはできません。

システムタイマーは、グローバルステートの優れた例です。


1

問題today()は、関数内で複数回呼び出された場合に異なる結果が得られる可能性があることです。

バグを引き起こす可能性のあるコード例を次に示します。

function doSomething(when)
{
     if(today() == when)
     {
           // open a resource or create a temp file.....
     }

     // do some other work

     if(today() == when)
     {
           // close the resource or delete temp file.....
     }
}

上記の例では可能です。2番目のifステートメントが実行されないこと。最初のものがそうであったとしても。リソースを悪い状態のままにします。


1

純粋な関数であるためには、同じパラメータを指定すると毎回同じ結果が得られなければなりません。

を呼び出すたびToday()に、同じパラメーター(なし)を提供しますが、必ずしも同じ結果(月曜日、火曜日など)を取得するわけではありません。


4
これは、約2年前に投稿されたトップアンサーで指摘され、説明された点を繰り返しているようです。このようなコンテンツで2年前の質問にぶつかる価値はほとんどありません
-gnat

1
私はstackexchangeがどのように機能するかについてあまり詳しくはありませんが、これは一番の質問であったので、すでにぶつかっていたと思いました。リピートポイントを作成する限り、複数の同様の回答が役立つとメタについて読んだことを覚えています。私は簡潔で潜在的に役立つと感じています。
ザンティエ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.