Haskell 哈斯克尔随机发生器。。。如何使其更易于使用?

Haskell 哈斯克尔随机发生器。。。如何使其更易于使用?,haskell,random,Haskell,Random,我遇到了与Haskell随机发生器相关的问题。在大学里,我不得不一路和Java打交道,所以现在我被它腐蚀了。 我正在Haskell开发一个游戏,现在我面临着“做某事的机会”,而这个机会需要像Int->Bool。在Java中,我会这样做 new Random().nextInt(100) 问题解决了! 在Haskell中,我必须选择monad IO中的内容或带有种子的内容。这些都不是我想要的。我真的不想在我的纯模型中使用IO monad,而且种子很难使用,因为每次我都需要记住我的新种子 有没有

我遇到了与Haskell随机发生器相关的问题。在大学里,我不得不一路和Java打交道,所以现在我被它腐蚀了。 我正在Haskell开发一个游戏,现在我面临着“做某事的机会”,而这个机会需要像
Int->Bool
。在Java中,我会这样做

new Random().nextInt(100) 
问题解决了!
在Haskell中,我必须选择monad IO中的内容或带有种子的内容。这些都不是我想要的。我真的不想在我的纯模型中使用IO monad,而且种子很难使用,因为每次我都需要记住我的新种子


有没有像Java的Random这样简单的东西?

对不起,但你必须接受它。 在纯函数式语言中,怎么会有一个函数在每次调用时为您提供不同的值?答案是:它不能-只有在IO单子或类似的状态单子中,你可以传递种子(并且不是每次都有相同的输入),这样的事情才会存在


您还可以查看这个问题“”,因为它与您的方向相同。

信不信由你,您必须在Haskell中使用与在Java中不同的方法。有几个软件包可以帮助你,但是你必须在头脑中有不同的态度才能成功地使用它们。以下是一些要点:

  • 无痛追踪种子
  • 用于高速、高质量的随机性
  • 另一种包装种子的方法是,以防你更喜欢玉米粒而不是单子
搜索“random”(随机)一词会找到很多、更多针对更具体需求的特定软件包。

有些不直观的是,既不输入也不输出的东西需要像处理过一样进行处理。假设您将其定义如下:

random100 = unsafePerformIO $ randomRIO (1, 100) -- This will not work!
这确实会给你一个随机数。您真正需要的是一种编码方法,每次都需要一个新的伪随机数。这意味着信息需要从一个随机数生成到下一个随机数生成。大多数语言只是忽略了这个“小细节”,但Haskell强迫您注意。当您发现自己能够在多线程上下文中正确地再现伪随机结果时,您可能会感谢Haskell

有很多方法可以建立这些连接,其中大部分已经提到过。如果您不愿意使用单子:请注意,将代码设置为单子形式通常是一件好事(但不要使用
IO
!)。接下来,您可能会遇到需要更多monad功能的情况,例如配置读卡器,然后所有的基础工作都会完成。

我认为,“您将不得不接受它”,既没有用处,也不正确。这实际上取决于您使用的抽象。如果您的应用程序自然绑定到一个monad,那么使用一个monadic随机数生成器是有意义的,它与Java的随机数生成器一样方便

在使用现代抽象的游戏中,您的应用程序自然绑定到函数式反应式编程(FRP),在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
movingPoint::MonadIO m=>(双精度,双精度)->导线m a(双精度,双精度)
移动点x0=
程序->执行
--随机淡入淡出。

使用IO Monad可见并不意味着你必须用IO破坏你的整个模型。。。只要一开始就把你的种子做好,然后把它交给你的纯计算。。。您的程序将是IO()类型,记得吗?那么你已经在IO Monad了。。。(如果你的游戏是100%纯的,那么玩起来一定不是很有趣!)你很快就会“腐蚀”你自己,游戏需要玩家的I/O:D关于这个问题的顶级答案:给出了一篇关于如何通过代码使有状态随机数生成器线程的精彩文章。“我真的不想在我的纯模型中使用IO monad”。在Java中,
new Random()
远远不是纯粹的。每次使用
nextInt
,您的
随机对象都会发生变异。因此,您的目标1)纯模型,2)类似Java的随机性,是冲突的,因为Java的随机性不是纯的。Java离我所看到的纯模型太远了:P,我的意思是。但事实上,我的注意力放错了头,我的头已经腐败了!谢谢大家的回复和评论!我投票否决了你,因为你没有真正给出解决方案。显而易见的解决办法是使用MonadRandomwell谢谢。。。但问题是,如果有简单的事情,他不喜欢伊奥·莫纳德。。。你认为《蒙娜多姆》比《蒙娜多姆》好得多吗?@Carsten,当然好得多,因为它不允许任意IO.nevermind。。。我知道OP不想进入“monad”区域或“do”符号或任何你不需要的东西。您可以像在Java中一样在任何地方使用IO。@Rotsor:尽管除非您也将所有内容都放入
ST
(monad transformers很有趣),您仍然需要处理不变性。即使这样,它也相当丑陋和毫无意义,以至于我希望任何一个理智的程序员都会放弃它。@delnan,我同意它丑陋和毫无意义(与Java编程的方式相同),但我不明白
ST
是多么必要
IO
可以做任何事情
ST
可以做更多。@Rotsor除了IO不能封装效果之外,这就是ST的全部要点。@augustss:啊,但是封装效果不是
IO
不能做什么的问题!相反,这是关于
IO
不能做的事情。不以非常精确的方式做事情比一直随心所欲更困难,但通常更有效。应该有一种方法将代码标记为非解决方案。因为很容易看到灰色的盒子,然后认为这就是答案