List 在Haskell中将随机生成的列表作为参数传递

List 在Haskell中将随机生成的列表作为参数传递,list,haskell,benchmarking,io-monad,criterion,List,Haskell,Benchmarking,Io Monad,Criterion,我是哈斯凯尔的新手,在整个IO事件上真的遇到了麻烦 我试图找出遍历haskell中的列表需要多长时间。我想生成一个随机数列表,并将其作为参数传递给函数,以便打印列表中的每个元素。我使用criteria包作为基准。代码如下: {-# LANGUAGE OverloadedStrings #-} import System.Random import Control.Exception import Criterion.Main printElements [] = return () print

我是哈斯凯尔的新手,在整个IO事件上真的遇到了麻烦

我试图找出遍历haskell中的列表需要多长时间。我想生成一个随机数列表,并将其作为参数传递给函数,以便打印列表中的每个元素。我使用criteria包作为基准。代码如下:

{-# 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]
               ]
  ]
简而言之,您需要将函数绑定到
IO
值,而不是尝试将其应用到
IO
值中包装的值

-- instead of whnf printElements (randomList 10)
randomList 10 >>= whnf printElements

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

randomList :: (...) => t1 -> IO [t]  -- not t1 -> [t]
因此,您不能直接使用
IO
操作可以生成的值列表;您需要使用monad实例将值绑定到适当的函数
whnf printElements
就是这样一个函数;它获取一个列表并返回一个
IO
操作

whnf printElements :: Show a => [a] -> IO ()
我们使用
>=
将函数“推”到
IO
值中,而不是拉出列表并将其传递给
whnf printElements
。该运算符的类型(专用于
IO
monad)为

(>>=) :: IO a -> (a -> IO b) -> IO b
在这种情况下,第一个
IO a
值是
randomList
返回的
IO[t]
whnf printElements
是我们绑定到的
a->IO b
函数。 结果是一个新的
IO
值,该值取第一个
IO
值,取出包装后的值,应用给定函数并返回结果

换句话说,
IO
monad本身负责将结果从
randomList
中分离出来,并将函数应用于它,而不是显式地执行


(您可能已经注意到我说过,
>=
将值绑定到函数,反之亦然。更准确的说法是,
>=
将它们绑定到一个
IO
操作中。)

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

-- instead of whnf printElements (randomList 10)
randomList 10 >>= whnf printElements

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

randomList :: (...) => t1 -> IO [t]  -- not t1 -> [t]
因此,您不能直接使用
IO
操作可以生成的值列表;您需要使用monad实例将值绑定到适当的函数
whnf printElements
就是这样一个函数;它获取一个列表并返回一个
IO
操作

whnf printElements :: Show a => [a] -> IO ()
我们使用
>=
将函数“推”到
IO
值中,而不是拉出列表并将其传递给
whnf printElements
。该运算符的类型(专用于
IO
monad)为

(>>=) :: IO a -> (a -> IO b) -> IO b
在这种情况下,第一个
IO a
值是
randomList
返回的
IO[t]
whnf printElements
是我们绑定到的
a->IO b
函数。 结果是一个新的
IO
值,该值取第一个
IO
值,取出包装后的值,应用给定函数并返回结果

换句话说,
IO
monad本身负责将结果从
randomList
中分离出来,并将函数应用于它,而不是显式地执行



(您可能已经注意到,我说过,
>=
将值绑定到函数,反之亦然。可以更准确地说,
>=
将它们绑定到一个
IO
操作中。)

尝试为每个函数指定一个显式类型签名。这是一个很好的练习,在学习的这一阶段提供了大量信息,并且有助于在Haskell学习/使用的所有阶段本地化编译消息。在基准测试期间,您将对一些
foo
重复执行
printElements foo
。您希望
foo
在每次执行中都有所不同吗?顺便说一句,使用此基准测试,您将在很大程度上测量打印内容所需的时间,因为生成随机数和遍历列表所需的时间相比可以忽略不计。请尝试为每个函数提供显式类型签名。这是一个很好的练习,在学习的这一阶段提供了大量信息,并且有助于在Haskell学习/使用的所有阶段本地化编译消息。在基准测试期间,您将对一些
foo
重复执行
printElements foo
。您希望
foo
在每次执行中都有所不同吗?顺便说一句,使用此基准测试,您将在很大程度上测量打印东西所需的时间,因为生成随机数和遍历列表所需的时间相比微不足道。当然
randomList 10>=whnf printElements
也可以编写
吗{list,当然,
randomList 10>=whnf printElements
也可以写入
do{list