OCaml:存储一些稍后使用的值是否会引入“副作用”?

发布于 2024-12-06 18:20:11 字数 317 浏览 0 评论 0原文

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

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

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

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

放低过去 2024-12-13 18:20:11

不;副作用是指使用赋值运算符 := 改变 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)

_畞蕅 2024-12-13 18:20:11

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

因此,类似:

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 等函数就地修改字符串即可。基本上,任何可以就地修改数据类型的函数都会产生副作用。

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:

let inc_nosf v = v+1

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:

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

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:

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

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:

let inc_sf r = r := !r+1

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:

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文