在 Haskell 中将随机生成的列表作为参数传递
Passing a randomly generated list as a parameter in Haskell
我是 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]
]
]
当我 运行 代码时出错:
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)’
简而言之,您需要将您的函数绑定到IO
值,而不是尝试应用它到IO
值中包含的值。
-- instead of whnf printElements (randomList 10)
randomList 10 >>= whnf printElements
randomList
不是 return 值列表;它 return 是一个 IO
动作,在执行时可以产生一个值列表。忽略实现带来的各种约束,类型为
randomList :: (...) => t1 -> IO [t] -- not t1 -> [t]
因此,您不能直接使用 IO
操作可以生成的值列表;您需要使用 monad 实例将值 绑定 到适当的函数。 whnf printElements
就是这样一个功能;它需要一个列表和 return 一个 IO
动作。
whnf printElements :: Show a => [a] -> IO ()
我们 "push" 函数 进入 一个 IO
值,而不是拉出列表并将其传递给 whnf printElements
23=]。该运算符的类型专门用于 IO
monad,是
(>>=) :: IO a -> (a -> IO b) -> IO b
在这种情况下,第一个 IO a
值是由 randomList
编辑的 IO [t]
值。 whnf printElements
是我们绑定的 a -> IO b
函数。
结果是一个新的 IO
值,它采用第一个 IO
值,提取包装值,应用给定的函数,然后 return 得到结果。
换句话说,IO
monad 本身负责从 randomList
中分离结果并将您的函数应用于它,而不是您明确地这样做。
(您可能已经注意到我说过 >>=
将一个值绑定到一个函数,反之亦然。更准确的说法是 >>=
将它们绑定到一个单一的IO
行动。)
我是 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]
]
]
当我 运行 代码时出错:
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)’
简而言之,您需要将您的函数绑定到IO
值,而不是尝试应用它到IO
值中包含的值。
-- instead of whnf printElements (randomList 10)
randomList 10 >>= whnf printElements
randomList
不是 return 值列表;它 return 是一个 IO
动作,在执行时可以产生一个值列表。忽略实现带来的各种约束,类型为
randomList :: (...) => t1 -> IO [t] -- not t1 -> [t]
因此,您不能直接使用 IO
操作可以生成的值列表;您需要使用 monad 实例将值 绑定 到适当的函数。 whnf printElements
就是这样一个功能;它需要一个列表和 return 一个 IO
动作。
whnf printElements :: Show a => [a] -> IO ()
我们 "push" 函数 进入 一个 IO
值,而不是拉出列表并将其传递给 whnf printElements
23=]。该运算符的类型专门用于 IO
monad,是
(>>=) :: IO a -> (a -> IO b) -> IO b
在这种情况下,第一个 IO a
值是由 randomList
编辑的 IO [t]
值。 whnf printElements
是我们绑定的 a -> IO b
函数。
结果是一个新的 IO
值,它采用第一个 IO
值,提取包装值,应用给定的函数,然后 return 得到结果。
换句话说,IO
monad 本身负责从 randomList
中分离结果并将您的函数应用于它,而不是您明确地这样做。
(您可能已经注意到我说过 >>=
将一个值绑定到一个函数,反之亦然。更准确的说法是 >>=
将它们绑定到一个单一的IO
行动。)