Functional programming OCaml:存储一些以后使用的值是否会引入;副作用;?

Functional programming OCaml:存储一些以后使用的值是否会引入;副作用;?,functional-programming,ocaml,side-effects,Functional Programming,Ocaml,Side Effects,对于家庭作业,我们被要求在不引入任何“副作用”的情况下完成任务。我在维基百科上查到了“副作用”,虽然我从理论上了解到它意味着“修改状态或与调用函数有可观察的交互”,但我很难弄清楚具体细节 例如,创建一个保存非编译时结果的值是否会带来副作用 假设我有(可能语法不完美): 这会带来副作用吗?我想我可能对副作用的定义中“改变一种状态”的含义感到困惑;副作用指的是,例如,使用赋值运算符:=对ref单元格进行变异,或名称所指的值随时间变化的其他事情。在本例中,myList是一个不可变的值,在程序中不会更改

对于家庭作业,我们被要求在不引入任何“副作用”的情况下完成任务。我在维基百科上查到了“副作用”,虽然我从理论上了解到它意味着“修改状态或与调用函数有可观察的交互”,但我很难弄清楚具体细节

例如,创建一个保存非编译时结果的值是否会带来副作用

假设我有(可能语法不完美):


这会带来副作用吗?我想我可能对副作用的定义中“改变一种状态”的含义感到困惑;副作用指的是,例如,使用赋值运算符
:=
ref
单元格进行变异,或名称所指的值随时间变化的其他事情。在本例中,
myList
是一个不可变的值,在程序中不会更改,因此它是无效果的

另见


思考这个问题的一个好方法是“我是否更改了任何以后的代码(包括以后再次运行相同的函数)可能看到的值以外的内容?”如果是,这是一个副作用。如果没有,那么你可以知道没有

比如说:

let inc_nosf v = v+1
let inc_sf r = r := !r+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_nosf v = v+1
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之类的函数就地修改字符串。基本上,任何可以修改数据类型的函数都会产生副作用。

谢谢,这个链接对于更好地理解函数编程和副作用非常有用。风格提示:“if expression then true else false”模式或其他类似模式在初学者中非常常见。如果你仔细想想,如果要选择If部分,表达式必须为真,而对于else部分,表达式必须为假。所以这个模式可以被删除并简化为“表达式”。你能展示一下代码吗?我绝对是一个初学者,可以使用一些指导。当然,它很简单:不是“if List.exists(=)7)myList然后true或者false;;”你可以写“List.exists(=)7)myList;;”。如果你停下来想一想原因,为什么这两个语句具有相同的语义,你会学到很多关于函数式(以及通用)编程的知识。这正是我用母语应该做的…不知道为什么我没有看到这里的联系哈哈。谢谢