Подтвердить что ты не робот

Как заставить оценку в 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 привязан только к thunk foo inputList?

В общем, как я могу убедиться, что выражение полностью оценивается до выполнения какого-либо действия?


Этот вопрос был задан несколько месяцев назад программистам (см. здесь) и принял принятый ответ, но он был закрыт как вне темы, потому что он принадлежит переполнение стека. Вопрос не может быть перенесен в переполнение стека, поскольку он старше 60 дней. Поэтому, соглашаясь с модераторами, я переписываю этот вопрос здесь и публикую принятый вопрос сам, потому что я думаю, что он содержит полезную информацию.

4b9b3361

Ответ 1

Ответ, первоначально заданный пользователем ysdx для программистов:

Действительно, версия не будет сравнивать ваш алгоритм. Поскольку 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

Я бы использовал расширение языка -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)