8

宿題の場合、「副作用」を発生させずにタスクを完了するように指示されています。ウィキペディアで「副作用」を調べましたが、理論的には「状態を変更したり、関数の呼び出しとの相互作用を観察したりする」という意味だと思いますが、詳細を理解するのに苦労しています。

たとえば、コンパイル時以外の結果を保持する値を作成すると、副作用が発生しますか?

私が持っていたと言う(構文的に完璧ではないかもしれません):

val myList = (someFunction x y);;
if List.exists ((=) 7) myList then true else false;;

これは副作用をもたらしますか?副作用の定義で「状態を変更する」とはどういう意味か混乱しているのではないでしょうか。

4

2 に答える 2

8

いいえ; 副作用とは、たとえばref、代入演算子を使用してセルを:=変更したり、名前で参照される値が時間の経過とともに変化したりすることを指します。この場合、myListはプログラム中に変更されない不変の値であるため、影響を受けません。

こちらもご覧ください

http://en.wikipedia.org/wiki/Referential_transparency_(computer_science)

于 2011-09-28T05:40:09.887 に答える
5

それについて考える良い方法は、「私が返す値以外に、後のコード (この同じ関数を後で再度実行することを含む) が見る可能性のあるものを変更したか?」ということです。もしそうなら、それは副作用です。そうでない場合は、存在しないことがわかります。

したがって、次のようなものです:

let inc_nosf v = v+1

整数 v より 1 大きい新しい値を返すだけなので、副作用はありません。したがって、ocaml トップレベルで次のコードを実行すると、対応する結果が得られます。

# let x = 5;;
val x : int = 5
# inc_nosf x;;
- : int = 6
# x;;
- : int = 5

ご覧のとおり、x の値は変化しませんでした。したがって、戻り値を保存しなかったため、実際には何もインクリメントされませんでした。関数自体は戻り値を変更するだけで、x 自体は変更しません。したがって、それを x に保存するには、次のようにする必要があります。

# let x = inc_nosf x;;
val x : int = 6
# x;;
- : int = 6

inc_nosf 関数には副作用がないため (つまり、他の変更を行うのではなく、戻り値を使用して外部の世界と通信するだけです)。

しかし、次のようなもの:

let inc_sf r = r := !r+1

r で表される参照に格納されている値を変更するため、副作用があります。したがって、トップ レベルで同様のコードを実行すると、代わりに次のようになります。

# let y = ref 5;;
val y : int ref = {contents = 5}
# inc_sf y;;
- : unit = ()
# y;;
- : int ref = {contents = 6}

したがって、この場合、戻り値をまだ保存していませんが、とにかくインクリメントされています。つまり、戻り値以外に変更があったに違いありません。この場合、その変更は:=、ref の保存された値を変更する代入でした。

経験則として、Ocaml では、参照、レコード、クラス、文字列、配列、およびハッシュ テーブルを使用しない場合、副作用のリスクを回避できます。ただし、String.set や String.fill などの関数を使用して文字列をその場で変更しない限り、文字列リテラルを安全に使用できます。基本的に、データ型をその場で変更できる関数は、副作用を引き起こします。

于 2011-09-28T06:03:39.440 に答える