OCaml:存储一些以后要使用的值会引入"副作用"吗?

Cas*_*ton 8 ocaml functional-programming side-effects

对于家庭作业,我们已被指示完成任务而不引入任何"副作用".我在维基百科上查找了"副作用",虽然我从理论上说它意味着"修改一个状态或者与调用函数有一个可观察的交互",但我很难搞清楚具体细节.

例如,创建一个保存非编译时间结果的值会引入副作用吗?

说我有(可能在语法上不完美):

val myList = (someFunction x y);;
if List.exists ((=) 7) myList then true else false;;
Run Code Online (Sandbox Code Playgroud)

这会引入副作用吗?我想也许我对"修改状态"在副作用定义中意味着什么感到困惑.

Bri*_*ian 8

没有; 副作用是指例如ref使用赋值运算符突变单元格:=,或者名称引用的值随时间变化的其他内容.在这种情况下,myList是一个永远不会在程序中更改的不可变值,因此它是无效的.

也可以看看

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


Kei*_*win 5

考虑它的一个好方法是"我有没有改变任何后来的代码(包括以后再次运行同一个函数)可能看到的除了我正在返回的值以外的其他代码?" 如果是这样,那就是副作用.如果没有,那么你可以知道没有一个.

所以,像:

let inc_nosf v = v+1
Run Code Online (Sandbox Code Playgroud)

没有副作用,因为它只返回一个多于整数v的新值.所以如果你在ocaml toplevel中运行以下代码,你会得到相应的结果:

# let x = 5;;
val x : int = 5
# inc_nosf x;;
- : int = 6
# x;;
- : int = 5
Run Code Online (Sandbox Code Playgroud)

如您所见,x的值没有改变.所以,既然我们没有保存返回值,那么没有真正增加.我们的函数本身只修改返回值,而不是x本身.所以要将其保存为x,我们必须这样做:

# let x = inc_nosf x;;
val x : int = 6
# x;;
- : int = 6
Run Code Online (Sandbox Code Playgroud)

由于inc_nosf函数没有副作用(也就是说,它只使用其返回值与外界通信,而不是进行任何其他更改).

但是像这样:

let inc_sf r = r := !r+1
Run Code Online (Sandbox Code Playgroud)

有副作用,因为它改变了由r表示的参考中存储的值.因此,如果您在顶级运行类似的代码,则会得到此代码:

# let y = ref 5;;
val y : int ref = {contents = 5}
# inc_sf y;;
- : unit = ()
# y;;
- : int ref = {contents = 6}
Run Code Online (Sandbox Code Playgroud)

因此,在这种情况下,即使我们仍然没有保存返回值,它仍然会增加.这意味着必须对返回值以外的其他内容进行更改.在这种情况下,该更改是:=用于更改ref的存储值的赋值.

作为一个好的经验法则,在Ocaml中,如果您避免使用refs,记录,类,字符串,数组和哈希表,那么您将避免任何副作用的风险.虽然您可以安全地使用字符串文字,只要您避免使用String.set或String.fill等函数修改字符串.基本上,任何可以修改数据类型的函数都会产生副作用.