Haskell: нельзя использовать getCPUTime - PullRequest
4 голосов
/ 20 октября 2010

у меня есть:

main :: IO ()
main = do
     iniciofibonaccimap <- getCPUTime
     let fibonaccimap = map fib listaVintesete
     fimfibonaccimap <- getCPUTime
     let difffibonaccimap = (fromIntegral (fimfibonaccimap - iniciofibonaccimap)) / (10^12)
     printf "Computation time fibonaccimap: %0.3f sec\n" (difffibonaccimap :: Double)

listaVintesete :: [Integer]
listaVintesete = replicate 100 27

fib :: Integer -> Integer
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

Но

*Main> main
Computation time fibonaccimap: 0.000 sec

Я не понимаю, почему это происходит. Помоги мне, спасибо.

Ответы [ 5 ]

7 голосов
/ 20 октября 2010

Как уже говорили другие, это связано с ленивой оценкой.Для принудительной оценки вы должны использовать пакет deepseq и BangPatterns:

{-# LANGUAGE BangPatterns #-}
import Control.DeepSeq
import Text.Printf
import System.CPUTime

main :: IO ()
main = do
 iniciofibonaccimap <- getCPUTime
 let !fibonaccimap = rnf $ map fib listaVintesete
 fimfibonaccimap <- getCPUTime
 let difffibonaccimap = (fromIntegral (fimfibonaccimap - iniciofibonaccimap)) / (10^12)
 printf "Computation time fibonaccimap: %0.3f sec\n" (difffibonaccimap :: Double)
...

. В приведенном выше коде вы должны заметить три вещи:

  1. .(по модулю ... функций, которые вы определили выше).Когда вы публикуете код для вопросов, пожалуйста, убедитесь, что он работает (iow, вы должны включить импорт)
  2. Использование rnf из deepseq.Это заставляет оценивать каждый элемент в списке.
  3. Шаблон взрыва на !fibonaccimap, что означает «делай это сейчас, не жди».Это приводит к тому, что список будет оцениваться в нормальной форме со слабой головой (в основном это только первый конструктор (:)).Без этого функция rnf сама осталась бы без оценки.

В результате:

$ ghc --make ds.hs
$ ./ds
Computation time fibonaccimap: 6.603 sec

Если вы собираетесь проводить сравнительный анализ, вам также следует использовать оптимизацию (-O2) и пакет Criterion вместо getCPUTime.

7 голосов
/ 20 октября 2010

Хаскель ленив. Вы вычисляете в строке

let fibonaccimap = map fib listaVintesete

на самом деле не происходит, пока вы не используете значение fibonaccimap. Таким образом, чтобы измерить используемое время, вам нужно ввести что-то, что заставит программу выполнить фактические вычисления.

ETA: Первоначально я предложил напечатать последний элемент для принудительной оценки. Как указывает TomMD, это далеко не достаточно хорошо - я настоятельно рекомендую прочитать его ответ здесь, чтобы реально работать с этим конкретным фрагментом кода.

4 голосов
/ 20 октября 2010

Я подозреваю, что вы "жертва" ленивая оценка . Ничто не заставляет вычислять fibonaccimap между вызовами синхронизации, поэтому он не вычисляется.

Редактировать Я подозреваю, что вы пытаетесь сравнить свой код, и в этом случае следует указать, что есть более совершенных способов до , которые делают это более надежно.

0 голосов
/ 20 октября 2010

Ленивая оценка на самом деле укусила тебя, как сказали другие ответы. В частности, «let» не заставляет вычислять выражение, он просто определяет переменную. Вычисления на самом деле не произойдут, пока что-то не потребует его значения, что, вероятно, не произойдет, пока действительному действию ввода-вывода не понадобится его значение. Таким образом, вы должны поместить свой оператор печати между вашими оценками getCPUTime. Конечно, это также даст время CPU , используемое для печати, но большая часть времени печати ожидает на IO. (Терминалы медленные.)

0 голосов
/ 20 октября 2010

10^12 - это целое число, которое заставляет значение fromIntegral быть целым числом, что означает, что difffibonaccimap назначается округленное значение, поэтому оно равно 0, если время меньше половины секунды. (В любом случае, это мое предположение. У меня нет времени на это разбираться.)

...