从函数返回随机值副作用?

时间:2010-12-08 19:38:39

标签: f# functional-programming

我正在处理一些F#代码,我正在处理一个函数,从一组字符串中返回一个随机字符串。假设我有这样的事情:

open System

let a = [|"a";"b";"c";"d"|]

let rstring (arr:string[]) =
   let r = new Random()
   arr.[r.Next(0,3)]

let resultstring = rstring a;;

我的问题是:我对函数式编程概念的理解是,如果给定的函数每次都有相同的输入,它应该总是返回相同的输出。那么在这种特殊情况下每次返回一个不同的字符串“副作用”?我只是好奇。

如果这是一个重复的问题,请指出我的原件,我会关闭它。我不确定用什么搜索字符串来查找与此相关的任何问题。


编辑:感谢所有人的所有信息。我似乎把参考透明度和缺乏副作用的概念混为一谈。所以,非常感谢所有人让我直截了当地感谢你的答案。

5 个答案:

答案 0 :(得分:13)

函数可以从同一输入返回不同值的唯一方法是通过副作用。其他人可能会另有说法,但他们错了。

(你可以声称'阅读系统时间'(显然是基于效果)不是一种效果。通过这个定义,它不是副作用。但是这个定义没有用,因为人们唯一的原因关注副作用的“关心”是因为它们会影响参照透明度。换句话说,参考透明度是唯一重要的,这个功能显然不是透明的。)

答案 1 :(得分:7)

“副作用”表示某个状态由函数更改,而不是返回值不同。在你的情况下,函数正在做两件事 - 它正在改变PRNG的状态并返回不同的值。

编辑:

我还要补充一点,如果函数总是返回给定输入的相同值,则称为幂等。 “副作用”还包括从外部状态读取的功能。例如:

int global = 0;
int function()
{
  return global;
}

有副作用。

答案 2 :(得分:3)

函数可以是非确定的。这不是副作用。如果它以某种方式改变了程序的状态以及返回值,则会产生副作用。我想说,副作用和非确定性都是函数式编程中函数与数学函数不同的方式。

答案 3 :(得分:2)

忽略随机生成器的实现细节(实际上需要副作用,理论上不需要),然后这个函数是副作用,但不是纯粹的。

基本上假设函数调用是一个oracle机器,完全基于什么都不返回随机数。某个地方有证据表明你无法做到这一点,但暂时想象一下就是这样。

如果你将PRNG函数视为这个oracle机器,每次你要求它给你一个随机数,那么它是副作用和不纯的,并且函数继承了它。

不违反参照透明度的副作用类型有时被称为“软副作用”正弦它不会改变程序的行为(注意:在你告诉我阅读时间改变之前)生成的数字的行为,函数调用的规范说该函数返回一个随机数。读取时钟是使规范工作的实现细节。更改时钟(在非常简并的情况下除外)不会改变该函数返回伪随机数的事实,因为规范没有详细说明该数字是什么。

软边效应的典型示例是日志记录,因为程序通常不会检查日志并根据它更改行为。

如果您想以功能纯粹的方式执行此操作,则必须实现状态monad。

http://fsharpcode.blogspot.com/2008/12/f-state-monad-type-state-state-state-of.html

基本上这样,让你说出一个随机数生成器和'a an int,然后你的控制流将杂质分离到一个函数并在排序上创建一个硬序。

在F#中执行此操作确实没有意义,因为不纯函数并不会导致问题(另一方面,具有副作用的函数)。

当然,monad是不纯的,但它很好地隔离了杂质。

答案 4 :(得分:1)

我不相信你的例子会被视为副作用。

http://en.wikipedia.org/wiki/Side_effect_(computer_science