Haskellを学んでいます。私が正しく理解していれば、Haskellの単純な関数は常に参照透過性です。それは、その出力が渡された引数のみに依存することを意味すると思いました。
ただし、関数は、外部スコープで定義されたf
別の関数を呼び出すことができます。g
したがって、その意味で、f
の戻り値はの定義に依存しますg
。また、関数g
はパラメーターとして渡されませf
ん-少なくとも明示的には渡されません。これは参照透過性を壊しませんか?
Haskellを学んでいます。私が正しく理解していれば、Haskellの単純な関数は常に参照透過性です。それは、その出力が渡された引数のみに依存することを意味すると思いました。
ただし、関数は、外部スコープで定義されたf
別の関数を呼び出すことができます。g
したがって、その意味で、f
の戻り値はの定義に依存しますg
。また、関数g
はパラメーターとして渡されませf
ん-少なくとも明示的には渡されません。これは参照透過性を壊しませんか?
重要なのは不変性です。
デフォルトで可変性を許可する言語であるJavascriptと比較して、この点を説明します。次のコードを検討してください。
f = function(x) {
return x;
}
g = function(y) {
f = function(x) {
return x+y;
}
}
これで、参照透過性を破ることができます。
f(1) -- returns 1
g(10)
f(1) -- returns 11
f
呼び出しをそれらの値に置き換えることができないため、参照透過性はありません。たとえば、コードでは
console.log(f(1))
g(10)
console.log(f(1))
の両方の呼び出しをf(1)
それらの値(1
)に置き換えて、
console.log(1)
g(10)
console.log(1)
つまり、1
コンソールに2回出力するコードです。しかし実際には、元のコードを実行すると、への呼び出しが介在するため、1
出力してから出力します。11
g(10)
すべての値が不変であるため、これはHaskellでは不可能です。言い換えれば、Haskellでは、g
スコープ外の別の関数の値を変更する関数を書くことはできません。Haskellでは、コードを壊すことなく、いつでも関数呼び出しをその値に置き換えることができます。
参照透過性とは、
f s = "Hello " ++ g s
g s = s ++ "!"
と見分けがつかない
f s = "Hello " ++ h s
where h s = s ++ "!"
g s = s ++ "!"
と
f s = "Hello " ++ s ++ "!"
g s = s ++ "!"
これは、の意味を変更せずにインラインg
化できることを意味します。f
f
の意味を変えるつもりなら、どういうわけかf
変えなければならないでしょう。g
どのように?
パラメータとして渡されない場合g
、それは「トップレベルの宣言」です。そして、そのような宣言は実行時に変更することはできません。それらを変更できる唯一の方法は、プログラムを再コンパイルする場合です。
したがって、関数が実行時に異なる結果を生成できる唯一の方法は、宣言された入力が変更された場合です。それは他のいくつかのものに「依存」しますが、これらの他のものはどれも実行時に変更できません。