Как заставить оценку в Haskell?
Я относительно новичок в Haskell, и я пытаюсь узнать, как различные действия могут выполняться последовательно, используя нотацию do. В частности, я пишу программу для сравнения алгоритма (функции)
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.
Последняя строка может нуждаться в преобразовании (например, в миллисекунды), но это не тема этого вопроса.
Это правильный способ измерить время, необходимое для вычисления функции foo для некоторого аргумента inputList?
Другими словами, будет ли выражение foo inputList
быть полностью уменьшенным перед действием end <- getCPUTime
выполняется? Или будет r
быть привязанным только к толпе foo inputList
?
В общем, как я могу убедиться, что выражение полностью вычислено перед выполнением какого-либо действия?
Этот вопрос был задан несколько месяцев назад программистам (см. Здесь) и на него был принят ответ, но он был закрыт как не по теме, поскольку он относится к переполнению стека. Вопрос не может быть перенесен в переполнение стека, поскольку он старше 60 дней. Итак, по согласованию с модераторами, я размещаю здесь вопрос и публикую принятый вопрос самостоятельно, потому что считаю, что он содержит некоторую полезную информацию.
2 ответа
Ответ, изначально предоставленный пользователем David Lenihan программистам:
Действительно, ваша версия не будет тестировать ваш алгоритм. Как
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
,
Я хотел бы использовать расширение языка -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)