【发布时间】:2018-06-25 12:20:42
【问题描述】:
我正在尝试使用以下代码生成一个随机索引 (Int):randomRIO (0, 2 :: Int)。但它会生成一个 IO Int,所以我不能这样做:[1,2,3] !! randomIndex。将 IO Int 转换为 Int 需要做什么?谢谢。
【问题讨论】:
我正在尝试使用以下代码生成一个随机索引 (Int):randomRIO (0, 2 :: Int)。但它会生成一个 IO Int,所以我不能这样做:[1,2,3] !! randomIndex。将 IO Int 转换为 Int 需要做什么?谢谢。
【问题讨论】:
...此代码:
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 和>>=。但如果这些中缀运算符和高阶类型签名对您来说很神秘,您也可以使用 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 <- action 和 let foo = action 之间的区别类似于 Python 中 foo = action() 和 foo = action 之间的区别。
【讨论】:
(>>=)或类似符号的情况下很好地使用do表示法。 sigfpe 的 The IO Monad for People who Simply Don't Care 文章是我所见过的最接近认真对待这种可能性的教程,所以如果你喜欢这个答案,我强烈推荐它作为下一步了解如何正确使用 do 块。
newCard:: Card newCard = do index <- randomRIO(0,7) return (getCards deck) !! index我想退卡,但它是IO卡
您无法将IO a 转换为a;但是您可以将使用 a 的函数转换为使用 IO a 的函数。两个最重要的转换是:
(<$>) :: (a -> b) -> (IO a -> IO b)
(=<<) :: (a -> IO b) -> (IO a -> IO b)
由于您要使用的函数,即\index -> [1,2,3] !! index,没有IO 返回类型,(<$>) 是更适合您的函数。所以:
System.Random> (\index -> [1,2,3] !! index) <$> randomRIO (0, 2)
1
【讨论】: