Haskell IO Int和Int

Ser*_*kin 4 monads haskell types io-monad

我最近开始学习Haskell.我正在尝试编写一个选择数组的随机元素的程序:

import System.Random

randomInt :: (Int, Int) -> IO Int
randomInt range = randomRIO range :: IO Int

choseRandom :: [a] -> a
choseRandom list = 
    length list
    >>=
        (\l -> randomInt(0,l-1))
        >>=
            (\num -> (list !! num))

main :: IO ()
main = undefined
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

Build FAILED

C:\Users\User\Haskell\Real\src\Main.hs: line 7, column 9:
  Couldn't match expected type `IO Int' with actual type `Int'

    In the return type of a call of `length'

    In the first argument of `(>>=)', namely `length list'

    In the first argument of `(>>=)', namely

      `length list >>= (\ l -> randomInt (0, l - 1))'
Run Code Online (Sandbox Code Playgroud)

我做错了什么?我第一次交易单子很难

Lee*_*Lee 7

由于您在内部使用IO choseRandom,因此需要更改类型签名:

choseRandom :: [a] -> IO a
Run Code Online (Sandbox Code Playgroud)

其次,您不需要>>=用来获取列表的长度.>>=有类型

Monad m => m a -> (a -> m b) -> m b
Run Code Online (Sandbox Code Playgroud)

类型length[a] -> Int,所以类型length listInt,不是monad.

您可以在致电时直接计算randomInt:

choseRandom :: [a] -> IO a
choseRandom list = 
    randomInt(0, length list) >>= (\num -> return (list !! num))
Run Code Online (Sandbox Code Playgroud)

这是一样的

choseRandom :: [a] -> IO a
choseRandom list = fmap (\num -> (list !! num)) (randomInt(0, length list))
Run Code Online (Sandbox Code Playgroud)

  • 一旦得到`fmap`的想法,丑陋的`(\num - >(list !! num))`可以缩短为`(list !!)`. (3认同)

Ing*_*ngo 7

我第一次交易单子很难

是的,你通过避免语法支持使其变得更难.就这样写吧:

choseRandom list = do
   let l = length list
   num <- randomInt(0,l-1)
   return (list !! num)
Run Code Online (Sandbox Code Playgroud)

这看起来不是更好吗?

现在到了这一点:randomRIO函数,如其类型所示,使用一些全局状态(可能是系统计时器).因此,您RandomRIO只能在IOMonad中使用结果.

另一种方法是初始化函数中的随机生成器main,并将此生成器传递给需要"随机"值的纯函数.