将随机生成的列表作为参数传递给Haskell

Aws*_*tic 0 benchmarking haskell list haskell-criterion io-monad

我是Haskell的新手,并且在整个IO事情上遇到了麻烦.

我试图找出遍历haskell列表所需的时间.我想生成一个随机数列表并将其作为参数传递给函数,以便我可以打印列表的每个元素.我正在使用CRITERION包作为基准.这是代码:

{-# LANGUAGE OverloadedStrings #-}
import System.Random
import Control.Exception
import Criterion.Main

printElements [] = return ()
printElements (x:xs) = do print(x)
                          printElements xs

randomList 0 = return []
randomList n = do
  x  <- randomRIO (1,100)
  xs <- randomList (n-1)
  return (x:xs)


main = defaultMain [
  bgroup "printElements" [ bench "[1,2,3]"  $ whnf printElements (randomList 10)
               , bench "[4,5,6]"  $ whnf printElements [4,5,6,4,2,5]
               , bench "[7,8,9]"  $ whnf printElements [7,8,9,2,3,4]
               , bench "[10,11,12]" $ whnf printElements [10,11, 12,4,5]
               ]
  ]
Run Code Online (Sandbox Code Playgroud)

运行代码时出错:

listtraversal.hs:18:67:
    Couldn't match expected type ‘[a0]’ with actual type ‘IO [t0]’
    In the second argument of ‘whnf’, namely ‘(randomList 10)’
    In the second argument of ‘($)’, namely
      ‘whnf printElements (randomList 10)’
Run Code Online (Sandbox Code Playgroud)

che*_*ner 5

简而言之,您需要函数绑定IO值,而不是尝试其应用于值中包含的IO值.

-- instead of whnf printElements (randomList 10)
randomList 10 >>= whnf printElements
Run Code Online (Sandbox Code Playgroud)

randomList不返回值列表; 它返回一个IO动作,当执行时,它可以生成一个值列表.忽略实现引起的各种约束,类型是

randomList :: (...) => t1 -> IO [t]  -- not t1 -> [t]
Run Code Online (Sandbox Code Playgroud)

因此,您无法直接使用IO操作可以生成的值列表; 您需要使用monad实例绑定到适当的函数.whnf printElements就是这样一个功能; 它需要一个列表并返回一个IO动作.

whnf printElements :: Show a => [a] -> IO ()
Run Code Online (Sandbox Code Playgroud)

我们不是将列表拉出并传递给它whnf printElements,而是使用"将"函数"推送" 一个IO值中>>=.该运营商的类型,专门为IOmonad,是

(>>=) :: IO a -> (a -> IO b) -> IO b
Run Code Online (Sandbox Code Playgroud)

在这种情况下,第一个IO a值是IO [t]返回的值randomList.whnf printElementsa -> IO b我们绑定的功能.结果是一个新IO值,它取第一个IO值,拉出包装值,应用给定函数,并返回结果.

换句话说,IOmonad本身负责将结果randomList与你的函数分开并将其应用于它,而不是你明确地去做.


(你可能已经注意到我已经说过>>=将一个值绑定到一个函数,反之亦然.或许更准确地说它将>>=它们绑定在一起就成了一个IO动作.)