我遇到与Haskell Random generator相关的问题。在大学里,我必须一直处理Java,所以现在我已经腐败了。
我正在Haskell开发一款游戏,现在我面临着“做某事的机会”这样的事情,而这种机会需要像Int -> Bool
。在Java中,我会完成
new Random().nextInt(100)
然后,问题解决了! 在Haskell中,我必须在monad IO中选择一些东西或者使用种子。这些都不是我想要的。我真的不想在我的纯模型中使用IO monad,种子很难用,因为我每次都需要记住我的新种子......
是否有像Java的Random这样简单的东西?
答案 0 :(得分:12)
信不信由你,你必须在Haskell中使用不同于Java的方法。有几个软件包可以帮助您,但是 必须在脑海中采取不同的态度才能成功使用它们。以下是一些提示:
在Hackage's package list上搜索“随机”一词会出现更多,更具体的包,以满足更具体的需求。
答案 1 :(得分:7)
抱歉,你必须忍受这一点。 如何在纯函数式语言中使用函数,在每次调用时为您提供不同的值?答案是:它不能 - 只有IO-Monad或类似于状态monad的东西,你可以传递你的种子(并且每次都没有相同的输入)可以存在这样的事情。
您也可以看一下这个问题“How can a time function exist in functional programming?”,因为它与您的方向相同。
答案 2 :(得分:2)
有点不直观,既不输入也不输出的东西需要像处理那样处理。假设您将其定义如下:
random100 = unsafePerformIO $ randomRIO (1, 100) -- This will not work!
这确实会给你一个随机数 - 在a way。您真正需要的是一种编码方式,每次都需要新伪随机数。这意味着信息需要从一个随机数生成到下一个。大多数语言都忽略了这个“小细节”,但Haskell强迫你注意。当你发现自己在多线程环境中正确地重现你的伪随机结果时,你可能会感谢Haskell。
您可以通过多种方式建立这些连接,其中大部分已经提到过。如果你不愿意使用monad:请注意,以monadic形式(但不使用IO
!)代码通常是一件好事。在路上,您可能会遇到需要更多monad功能的情况,例如配置阅读器 - 然后所有基础工作都已完成。
答案 3 :(得分:2)
我认为,“你将不得不忍受”,既不有用也不正确。这实际上取决于您使用的抽象。如果你的应用程序自然地绑定到monad,那么使用monadic随机数生成器是有意义的,这与Java的随机数生成器一样方便。
对于使用现代抽象的游戏,您的应用程序自然会受到功能反应式编程(FRP)的约束,其中生成随机数根本不是问题,并且不需要您明确地传递生成器。使用netwire库的示例:
movingPoint :: MonadIO m => (Double, Double) -> Wire m a (Double, Double)
movingPoint x0 =
proc _ -> do
-- Randomly fades in and out of existence.
visible <- wackelkontakt -< ()
require -< (visible, ())
-- 'rnd' is a random value between -1 and 1.
rnd <- noise1 -< ()
-- dx is the velocity.
let dx = (sin &&& cos) (rnd * pi)
-- Integration of dx over time gives us the point's position.
-- x0 is the starting point.
integral x0 -< dx
有没有办法更简单,更简洁地表达这一点?我猜不会。 FRP也证明了Zhen的评论是错误的。它可以纯粹处理用户输入。