2013-01-04 34 views
19

我对Haskell比较新,我想了解如何使用符号按顺序执行不同的动作。 特别是,我写一个程序,以基准算法(函数)如何在Haskell中强制进行评估?

foo :: [String] -> [String] 

为了这个目的,我想编写一个函数像

import System.CPUTime 

benchmark :: [String] -> IO Integer 
benchmark inputList = do 
         start <- getCPUTime 
         let r = foo inputList 
         end <- getCPUTime 
         return (end - start) -- Possible conversion needed. 

最后一行可能需要一个转换(例如到毫秒),但这不是这个问题的主题。

这是测量在某些参数inputList上计算函数foo所需时间的正确方法吗?

换句话说,在执行动作end <- getCPUTime之前,表达式foo inputList会被完全减少吗?或者r只会绑定到thunk foo inputList

更一般来说,如何确保在执行某个操作之前完全评估表达式?


这个问题被问得几个月前程序员(见here),并已被接受的答案有,但因为它属于对堆栈溢出它已关闭的题外话。这个问题不能转移到堆栈溢出,因为它超过了60天。所以,根据协调人的协议,我在这里重新发布这个问题,并自己发布接受的问题,因为我认为它包含一些有用的信息。

+4

如果你是在基准有兴趣,你可能要检查出[标准](http://hackage.haskell.org/package/criterion ) 图书馆。 – hugomg

+0

到达最后一行时,'foo'功能将不会执行。 Haskell函数只按需求进行评估,所以在赋值到'end'之前,你需要用'r'值做一些事情。 –

回答

15

回答最初由用户ysdxon programmers给出:

你的确版本不会基准你的算法。由于r未使用,因此不会进行评估。

你应该能够DeepSeq做到这一点:

benchmark :: [String] -> IO Integer 
benchmark inputList = do 
        start <- getCPUTime 
        let r = foo inputList 
        end <- r `deepseq` getCPUTime 
        return (end - start) 

a `deepseq` b)是一些“神奇”表现,迫使的a完整/递归计算返回b之前。

+2

通常的做法是让自己免除为他人工作的功劳,那就是制作答案社区维基。然后答案仍然可以upvoted /接受,但你不会得到信用:) –

+1

我不知道,谢谢。我已经设置了社区wiki标签。现在,如果他们碰巧再次读到这两个upvoters可以删除upvote。 – Giorgio

6

我会使用语言扩展-XBangPatterns,我觉得在这种情况下很有表现力。所以,你不得不说,“let !r = foo inputList”,如:

{-# LANGUAGE BangPatterns #-} 
import System.CPUTime 

benchmark :: [String] -> IO Integer 
benchmark inputList = do 
         start <- getCPUTime 
         let !r = foo inputList 
         end <- getCPUTime 
         return (end - start) 
+1

这只会评估结果到最外层的构造函数,在这里,需要完整的评估。 –

+1

做爆炸模式确保完整的评估或将表达式减少到弱头正常形式吗(http://stackoverflow.com/questions/6872898/haskell-what-is-weak-head-normal-form)? – Giorgio

+0

你也可以在foo中使用BangPatterns。 –