You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell基准测试中传递随机生成列表参数报错求助

解决Haskell Criterion基准测试中的IO类型不匹配问题

嘿,这个问题其实是因为你混淆了Criterion中纯函数基准测试和IO操作基准测试的用法,我来给你一步步理清楚:

错误原因分析

你看报错信息里说的:Couldn't match expected type ‘[a0]’ with actual type ‘IO [t0]’,问题出在这一行:

bench "[1,2,3]" $ whnf printElements (randomList 10)
  • whnf是Criterion用来测试纯函数的工具:它需要你传入一个纯函数(这里是printElements,类型是Show a => [a] -> IO ())和一个纯输入值(也就是[a]类型的列表)。
  • 但randomList 10返回的是IO [Int]——这是一个IO动作,不是纯列表,所以类型完全不匹配,自然报错了。

另外还要注意:printElements本身虽然接受纯列表,但它返回的是IO (),所以如果你只是用whnf测试printElements someList,其实测的是"生成IO动作"的耗时,而不是执行打印操作的耗时——这几乎没意义,因为真正耗时的是打印本身。

两种解决方案

方案1:测试"生成随机列表+打印"的整体IO耗时

如果你想测的是从生成随机数到打印完成的完整流程,应该把这两个步骤合并成一个IO动作,然后用Criterion专门测试IO的函数whnfIO或者nfIO:

修改后的完整代码:

{-# 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" [
        -- 把生成列表和打印合并成一个IO动作,用whnfIO测试
        bench "random-list-10" $ whnfIO (randomList 10 >>= printElements),
        -- 纯列表的测试也要改成测试IO动作的执行
        bench "[4,5,6,...]" $ whnfIO (printElements [4,5,6,4,2,5]),
        bench "[7,8,9,...]" $ whnfIO (printElements [7,8,9,2,3,4]),
        bench "[10,11,12,...]" $ whnfIO (printElements [10,11,12,4,5])
    ]
]

这里randomList 10 >>= printElements的意思是:先执行randomList 10得到随机列表,再把这个列表传给printElements执行打印,最终得到一个IO ()动作,whnfIO会帮你执行这个动作并测量耗时。

方案2:先固定随机列表,再测试打印纯列表的耗时

如果你想避免每次测试生成不同的随机列表(防止随机数差异影响基准结果),可以先在main里生成一次随机列表,再把这个纯列表传给whnf:

修改后的代码:

{-# 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 = do
    -- 先在IO中生成纯随机列表
    randList <- randomList 10
    defaultMain [
        bgroup "printElements" [
            -- 现在randList是纯[Int],和whnf的要求匹配
            bench "random-list-10" $ whnf printElements randList,
            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]
        ]
    ]

注意:这种方案测的是printElements在固定列表上的打印耗时,生成随机列表的时间不会被算进基准测试里。

小提醒

  • 如果你主要关心打印操作的性能,方案1更贴合你的需求,因为它包含了生成列表到打印的完整流程。
  • whnfIO和nfIO的区别:whnfIO只评估到弱头范式(比如对于IO动作,就是执行它),nfIO会完全评估结果,对于IO ()来说两者区别不大,但如果你的IO返回复杂值,可能需要选nfIO。

内容的提问来源于stack exchange,提问作者AR17

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:35:22