我想做一个Haskell函数,它可以从给定的列表中挑选出一个随机数。我的类型签名是:
randomPick :: [a] -> a 我该怎么办?
发布于 2010-05-28 10:16:26
在Haskell中,定义“纯”函数的一部分是它是的,也就是说,它可以与计算结果互换。这意味着每次评估的结果都必须是相同的。因此,你想要的功能恐怕是不可能的。要在Haskell中生成随机数,函数需要执行以下两项操作之一:
获取并返回伪随机数生成器,例如:
randomPick :: RNG -> [a] -> (a, RNG)或者使用IO访问来自“外部世界”的随机性:
randomPick :: [a] -> IO a两种样式都是由the module System.Random提供的。此外,在前一种情况下,传递PRNG可以使用State monad或special-purpose Random monad抽象出来。
发布于 2010-05-28 10:14:53
您所描述的内容不能在纯函数代码中完成。
纯函数代码意味着您每次都会为相同的输入获得相同的输出。由于根据定义,随机化函数为相同的输入提供不同的输出,这在纯函数代码中是不可能的。
除非您传递一个额外的值,如@camccann's answer中所述。从技术上讲,它甚至不需要像RNG那样高级,这取决于您的需求。你可以传递一个整数,然后乘以10,再减去3(或其他任何东西),然后取它的模来得到你的索引。那么你的函数仍然是纯的,但是你可以直接控制随机性。
另一种选择是使用RandomRIO在一个范围内生成一个数字,然后您可以使用该数字从列表中选择一个索引。这将要求您进入IO monad。
发布于 2010-05-28 16:52:16
如果你想在纯函数代码中使用随机数生成器,而不是显式地传递生成器状态,那么你可以使用状态monad (或者monad transformer)并隐藏管道。状态monad仍然是参照透明的,并且它是安全和正常的转义状态monad。如果你想要真正的局部可变状态,在外部是纯函数的,你也可以使用ST monad。
下面是我写的一些有用的代码,有时也会用到:
rand :: (Random a, RandomGen g, MonadState g m) => a -> a -> m a
rand lo hi = do
r <- get
let (val, r') = randomR (lo, hi) r
put r'
return valhttps://stackoverflow.com/questions/2926267
复制相似问题