OCaml:存储一些稍后使用的值是否会引入“副作用”?
对于家庭作业,我们被指示要在不引入任何“副作用”的情况下完成任务。我在维基百科上查找了“副作用”,尽管我知道理论上它意味着“修改状态或与调用函数有可观察到的交互”,但我很难弄清楚具体细节。
例如,创建一个保存非编译时结果的值是否会引入副作用?
假设我有(语法上可能不完美):
val myList = (someFunction x y);;
if List.exists ((=) 7) myList then true else false;;
这会带来副作用吗?我想也许我对副作用定义中“修改状态”的含义感到困惑。
For a homework assignment, we've been instructed to complete a task without introducing any "side-effects". I've looked up "side-effects" on Wikipedia, and though I get that in theory it means "modifies a state or has an observable interaction with calling functions", I'm having trouble figuring out specifics.
For example, would creating a value that holds a non-compile time result be introducing side effects?
Say I had (might not be syntactically perfect):
val myList = (someFunction x y);;
if List.exists ((=) 7) myList then true else false;;
Would this introduce side-effects? I guess maybe I'm confused on what "modifies a state" means in the definition of side-effects.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不;副作用是指使用赋值运算符
:=
改变ref
单元格,或者名称引用的值随时间变化的其他情况。在这种情况下,myList
是一个不可变的值,在程序期间永远不会改变,因此它是无效果的。另请参阅
http://en.wikipedia.org/wiki/Referential_transparency_(computer_science)
No; a side-effect refers to e.g. mutating a
ref
cell with the assignment operator:=
, or other things where the value referred to by a name changes over time. In this case,myList
is an immutable value that never changes during the program, thus it is effect-free.See also
http://en.wikipedia.org/wiki/Referential_transparency_(computer_science)
思考这个问题的一个好方法是“除了我返回的值之外,我是否更改了任何后续代码(包括稍后再次运行相同的函数)可能看到的任何内容?”如果是这样,那就是副作用。如果没有,那么您就知道不存在。
因此,类似:
没有副作用,因为它只是返回一个比整数 v 大 1 的新值。因此,如果您在 ocaml 顶层运行以下代码,您将得到相应的结果:
如您所见,该值x 的值没有改变。因此,由于我们没有保存返回值,因此没有任何内容真正增加。我们的函数本身只修改返回值,而不修改 x 本身。因此,要将其保存到 x 中,我们必须这样做:
由于 inc_nosf 函数没有副作用(即,它仅使用其返回值与外界通信,而不是通过进行任何其他更改)。
但类似:
具有副作用,因为它更改了存储在 r 表示的引用中的值。因此,如果您在顶层运行类似的代码,您会得到以下结果:
因此,在这种情况下,即使我们仍然不保存返回值,它仍然会递增。这意味着除了返回值之外,肯定还有其他东西发生了变化。在本例中,该更改是使用
:=
的赋值,它更改了 ref 的存储值。作为一个好的经验法则,在 Ocaml 中,如果避免使用引用、记录、类、字符串、数组和哈希表,那么您将避免任何副作用的风险。尽管您可以安全地使用字符串文字,但只要避免使用 String.set 或 String.fill 等函数就地修改字符串即可。基本上,任何可以就地修改数据类型的函数都会产生副作用。
A good way to think about it is "have I changed anything which any later code (including running this same function again later) could ever possibly see other than the value I'm returning?" If so, that's a side effect. If not, then you can know that there isn't one.
So, something like:
has no side effects because it just returns a new value which is one more than an integer v. So if you run the following code in the ocaml toplevel, you get the corresponding results:
As you can see, the value of x didn't change. So, since we didn't save the return value, then nothing really got incremented. Our function itself only modifies the return value, not x itself. So to save it into x, we'd have to do:
Since the inc_nosf function has no side effects (that is, it only communicates with the outside world using its return value, not by making any other changes).
But something like:
has side effects because it changes the value stored in the reference represented by r. So if you run similar code in the top level, you get this, instead:
So, in this case, even though we still don't save the return value, it got incremented anyway. That means there must have been changes to something other than the return value. In this case, that change was the assignment using
:=
which changed the stored value of the ref.As a good rule of thumb, in Ocaml, if you avoid using refs, records, classes, strings, arrays, and hash tables, then you will avoid any risk of side effects. Although you can safely use string literals as long as you avoid modifying the string in place using functions like String.set or String.fill. Basically, any function which can modify a data type in place will cause a side effect.