让vs做monadic值[重复]

问题描述 投票:-1回答:1

这个问题在这里已有答案:

在尝试使用monadic值时,使用letdo有什么区别? (不确定这是否是正确的表达方式)

例如:

--import System.Random

*Main> dupRand = let i = randomRIO (1, 10) in sequence [i, i]
*Main> :t dupRand
dupRand :: (Random a, Num a) => IO [a]
*Main> dupRand
[8,3]
*Main> dupRand
[2,9]
*Main> dupRand
[9,5]

*Main> dupRand2 = do i <- randomRIO (1, 10); pure [i, i]
*Main> :t dupRand2
dupRand2 :: (Random a, Num a) => IO [a]
*Main> dupRand2
[6,6]
*Main> dupRand2
[9,9]
*Main> dupRand2
[5,5]

为什么在dupRand2中,函数成功复制了一个随机值,而在dupRand中,函数看起来好像生成了两个随机值?

haskell random monads let
1个回答
5
投票

dupRand =
  let i = randomRIO (1, 10)
  in sequence [i, i]

你将i绑定到一个IO动作,当它运行时,会产生一个随机数。您列出了两个元素,每个元素都包含该操作。现在

sequence
  :: (Traversable t, Monad m)
  => t (m a) -> m (t a)

在这种情况下,Traversable[]MonadIO,所以

sequence :: [IO a] -> IO [a]

这样做是在列表中运行每个IO操作,按顺序返回其结果列表。因此,当我们运行sequence [i, i]时,我们得到一个随机数,得到一个随机数,然后生成一个包含它们的列表。

dupRand2没有进行类型检查。我猜你的意思

dupRand2 = do
  i <- randomRIO (1, 10)
  pure [i, i]

这是语法糖

dupRand2 =
  randomRIO (1, 10) >>= \i ->
    pure [i, i]

运行时,此操作将i绑定到一个随机数(而不是生成一个的动作),然后返回一个i重复两次的列表。

© www.soinside.com 2019 - 2024. All rights reserved.