简体   繁体   English

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

[英]Passing a randomly generated list as a parameter in Haskell

I am new to Haskell and really having trouble with the whole IO thing. 我是Haskell的新手,确实遇到了整个IO问题。

I am trying to find out how long it takes to traverse a list in haskell. 我试图找出在Haskell中遍历列表需要多长时间。 I wanted to generate a list of random numbers and pass it as a parameter to a function so that I can print each element of the list. 我想生成一个随机数列表,并将其作为参数传递给函数,以便我可以打印列表中的每个元素。 I am using CRITERION package for the benchmark. 我正在使用CRITERION软件包作为基准。 Here is the code: 这是代码:

{-# 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]
               ]
  ]

Error when I run the code: 运行代码时出错:

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)’

Put briefly, you need to bind your function to the IO value, instead of trying to apply it to the value wrapped inside the IO value. 简而言之,您需要函数绑定IO值,而不是尝试其应用于包装在IO值内的值。

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

randomList does not return a list of values; randomList不返回值列表; it returns an IO action that, when executed, can produce a list of values. 它返回一个IO操作,该操作在执行时可以产生值列表。 Ignoring the various constraints induced by the implementation, the type is 忽略由实现引起的各种约束,类型为

randomList :: (...) => t1 -> IO [t]  -- not t1 -> [t]

As such, you can't directly work with the list of values that the IO action can produce; 因此,您不能直接使用IO操作可以产生的值列表; you need to use the monad instance to bind the value to an appropriate function. 您需要使用monad实例绑定到适当的函数。 whnf printElements is one such function; whnf printElements是这样的功能之一; it takes a list and returns an IO action. 它需要一个列表并返回IO操作。

whnf printElements :: Show a => [a] -> IO ()

Instead of pulling the list out and passing it to whnf printElements , we "push" the function into an IO value using >>= . 不用拉出列表并将其传递给whnf printElements ,而是使用>>=将函数“推” IO值中。 That operator's type, specialized to the IO monad, is 专门用于IO monad的运算符类型为

(>>=) :: IO a -> (a -> IO b) -> IO b

In this case, the first IO a value is the IO [t] value returned by randomList . 在这种情况下,第一个IO a值是randomList返回的IO [t]值。 whnf printElements is the a -> IO b function we bind to. whnf printElements是我们绑定到的whnf printElements a -> IO b函数。 The result is a new IO value that take the first IO value, pulls out the wrapped value, applies the given function, and returns the result. 结果是一个新的IO值,该值将采用第一个IO值,取出包装的值,应用给定的函数,然后返回结果。

In other words, the IO monad itself takes care of pulling apart the result from randomList and applying your function to it, rather than you doing it explicitly. 换句话说, IO monad本身负责将结果与randomList并对其应用功能,而不是您明确地进行操作。


(You might have noticed that I've said that >>= binds a value to a function and vice versa. It is perhaps more accurate to say that >>= binds them together into a single IO action.) (您可能已经注意到,我曾经说过>>=将值绑定到函数,反之亦然。说>>=将它们绑定在一起成为一个IO操作,可能更准确。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM