【问题标题】:How to generate random Int in Haskell? [duplicate]如何在 Haskell 中生成随机 Int? [复制]
【发布时间】:2018-06-25 12:20:42
【问题描述】:

我正在尝试使用以下代码生成一个随机索引 (Int):randomRIO (0, 2 :: Int)。但它会生成一个 IO Int,所以我不能这样做:[1,2,3] !! randomIndex。将 IO Int 转换为 Int 需要做什么?谢谢。

【问题讨论】:

    标签: haskell random io int


    【解决方案1】:

    ...此代码:randomRIO (0, 2 :: Int)。但它会生成一个IO Int...

    不,它一个IO Int 值。这样的值类似于过程语言中的“函数”int f()。如果这是,比如说,Python,那么你也不能只写

    Python 3.5.2 (default, Nov 23 2017, 16:37:01) 
    Type 'copyright', 'credits' or 'license' for more information
    IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
    
    In [1]: import random
    
    In [2]: def f():
       ...:     return random.randint(0,2)
       ...: 
    
    In [3]: [1,2,3][f]
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-3-74d3c2a164a4> in <module>()
    ----> 1 [1,2,3][f]
    
    TypeError: list indices must be integers or slices, not function
    

    相反,您需要调用该操作。只有这样实际上会产生一个Int 号码。在大多数语言中,这只是通过提供参数来完成,在这种情况下只是空元组()

    In [4]: [1,2,3][f()]
    Out[4]: 2
    

    但这混合了两个不同的概念,即提供参数和引起副作用。 (在这种情况下,副作用是修改了内置随机生成器的状态,因此您不会每次都得到相同的数字。)

    Haskell 做得更好,它有专门的运算符来整理副作用的顺序。正如丹尼尔瓦格纳所说,这些是fmap&gt;&gt;=。但如果这些中缀运算符和高阶类型签名对您来说很神秘,您也可以使用 Haskell 的 do 表示法,它实际上只是同一事物的语法糖:

    main :: IO ()
    main = do
       randomIndex <- randomRIO (0,2)
       print $ [1,2,3] !! randomIndex
    

    或者,在 ghci 提示符下(本质上是一大块 IO-do-block)

    GHCi, version 8.2.1: http://www.haskell.org/ghc/  :? for help
    Loaded GHCi configuration from /home/sagemuej/.ghci
    Loaded GHCi configuration from /home/sagemuej/.ghc/ghci.conf
    Prelude> :m +System.Random
    Prelude System.Random> randomIndex <- randomRIO (0,2 :: Int)
    Prelude System.Random> [1,2,3] !! randomIndex
    1
    

    foo &lt;- actionlet foo = action 之间的区别类似于 Python 中 foo = action()foo = action 之间的区别。

    【讨论】:

    • 我经常想知道初学者是否有可能在没有牢牢掌握(&gt;&gt;=)或类似符号的情况下很好地使用do表示法。 sigfpe 的 The IO Monad for People who Simply Don't Care 文章是我所见过的最接近认真对待这种可能性的教程,所以如果你喜欢这个答案,我强烈推荐它作为下一步了解如何正确使用 do 块。
    • 但我的真实密码是:newCard:: Card newCard = do index &lt;- randomRIO(0,7) return (getCards deck) !! index我想退卡,但它是IO卡
    • “我想退卡”——不,你没有。除非您希望每场比赛中的每张牌都相同。
    • @leftaroundabout 所以只能在输出中生成随机数?谢谢你的帮助。是不是我看到了这个 System.Random 包,并认为我可以用它来做我想做的事情......
    【解决方案2】:

    您无法将IO a 转换为a;但是您可以将使用 a 的函数转换为使用 IO a 的函数。两个最重要的转换是:

    (<$>) :: (a ->    b) -> (IO a -> IO b)
    (=<<) :: (a -> IO b) -> (IO a -> IO b)
    

    由于您要使用的函数,即\index -&gt; [1,2,3] !! index,没有IO 返回类型,(&lt;$&gt;) 是更适合您的函数。所以:

    System.Random> (\index -> [1,2,3] !! index) <$> randomRIO (0, 2)
    1
    

    【讨论】:

      猜你喜欢
      • 2015-01-15
      • 1970-01-01
      • 2020-04-19
      • 1970-01-01
      • 1970-01-01
      • 2013-07-15
      • 2012-10-25
      • 1970-01-01
      相关资源
      最近更新 更多