Haskell 一次创建多个标准基准

Haskell 一次创建多个标准基准,haskell,criterion,Haskell,Criterion,此代码编译和运行时不会出现问题: module Main where import Criterion.Main main :: IO () main = defaultMain [env (return $ [1,2]) (\is -> bgroup "group" (benchmarks is))] timesTwo :: Int -> Int timesTwo i = 2 * i benchmarks :: [Int

此代码编译和运行时不会出现问题:

module Main where

import Criterion.Main

main :: IO ()
main =
  defaultMain
    [env (return $ [1,2])
         (\is ->
            bgroup "group" (benchmarks is))]

timesTwo :: Int -> Int
timesTwo i = 2 * i

benchmarks :: [Int] -> [Benchmark]
benchmarks is = [ bench "foo" $ nf timesTwo (is !! 0)
                , bench "foo" $ nf timesTwo (is !! 1) ]
然而,如果我将
基准
函数更改为

benchmarks :: [Int] -> [Benchmark]
benchmarks is = map (\i -> bench "foo" $ nf timesTwo i) is
它仍在编译,但我遇到以下运行时错误:

ghci> main
*** Exception: Criterion atttempted to retrieve a non-existent environment!
        Perhaps you forgot to use lazy pattern matching in a function which
        constructs benchmarks from an environment?
        (see the documentation for `env` for details)
我如何解决这个问题

如您所见,我的目标是映射从环境中获取的列表,以便将其转换为可用于Criteria的
基准
s
列表


注意:我最终希望使用更多的元素,而不仅仅是两个,所以元组不是我在这里想要的。

env
非常严格。你不能在这里用。在
env
下创建的基准的结构不能依赖于环境。也就是说,被基准测试的代码可以使用环境,但基准测试本身的组织、命名等方式无法使用环境。这是因为
标准
有时会传递
124;
而不是真实环境,当它只想检查基准的结构而不执行它们时。当您使用
,基准的组织是手工给出的,即使
为=124;

benchmarks _|_ = [ bench "foo" $ nf timesTwo _|_ -- _|_ !! n = _|_; nf is not strict
                 , bench "foo" $ nf timesTwo _|_ ] -- "bench"s are still there
但是
map
打破了这一点:

benchmarks _|_ = map _etc _|_
               = case _|_ of -- definition of map
                      [] -> []
                      x:xs -> _etc x : map _etc xs
               = _|_ -- benchmark structure gone
您最好不要使用
env

main = do is <- _ -- however you calculate is
          defaultMain $ bgroup "group" $ benchmark is

main=do是对于不同规模的基准测试,我通常会这样做:

module Main (main) where

import Criterion.Main
import System.Random
import Control.Monad

import qualified Data.List
import qualified Data.Sequence

int :: Int -> IO Int
int n = randomRIO (0,n)

benchAtSize :: Int -> Benchmark
benchAtSize n =
    env (replicateM n (int n)) $
    \xs ->
         bgroup (show n)
           [ bench "Data.List"     $ nf Data.List.sort xs
           , bench "Data.Sequence" $ nf (Data.Sequence.sort . Data.Sequence.fromList) xs
           ]

main :: IO ()
main = defaultMain (map benchAtSize [100, 1000, 10000])

env
有助于确保在同一个样本上比较两个不同的函数,而且它不是为了在运行基准测试之前计算整个数据集而设计的。此外,由于在对其范围内的任何内容进行基准测试期间,
env
创建的所有数据都保存在内存中,因此您希望尽可能将其最小化,以减少基准测试时的开销。

如何从环境中获取列表?你能静态地知道它的长度吗?@oisdk在实践中,我将使用编译时我自己知道的数字。想想这个:[10010001000000]我的目标是做一个“大O”基准。(如果您知道“大O”分析的更好方法,请随时提出建议。)