2013-01-04 22 views
19

Jestem względnie nowy dla Haskella i staram się nauczyć, jak różne akcje mogą być wykonywane sekwencyjnie za pomocą notacji. W szczególności, piszę program do benchmarku algorytm (funkcja)Jak wymusić ocenę w Haskell?

foo :: [String] -> [String] 

W tym celu chciałbym napisać funkcję jak

import System.CPUTime 

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

Ostatnia linia może wymagać konwersji (np. do milisekund), ale nie jest to tematem tego pytania.

Czy to jest właściwy sposób pomiaru czasu potrzebnego do obliczenia funkcji foo na niektórych argumentach inputList?

Innymi słowy, czy wyrażenie foo inputList zostanie całkowicie zredukowane przed wykonaniem działania end <- getCPUTime? Czy też r będzie związany tylko z Thunk foo inputList?

Ogólniej, jak mogę się upewnić, że wyrażenie zostanie w pełni ocenione przed wykonaniem jakiejś czynności?


To pytanie został poproszony kilka miesięcy temu na programistów (patrz here) i miał zaakceptowane odpowiedź tam, ale został zamknięty jako off-topic, ponieważ należy na przepełnienie stosu. Nie można przenieść pytania do przepełnienia stosu, ponieważ jest starsze niż 60 dni. Tak więc, w porozumieniu z moderatorami, ponawiam pytanie tutaj i sam przesyłam zaakceptowane pytanie, ponieważ uważam, że zawiera ono pewne przydatne informacje.

+4

Jeśli interesuje tylko benchmarkingu, warto zapoznać się z [kryterium] (http://hackage.haskell.org/package/criterion) biblioteka. – hugomg

+0

Funkcja 'foo' nie zostanie uruchomiona przed osiągnięciem ostatniej linii. Funkcje Haskell są oceniane tylko na żądanie, więc będziesz musiał zrobić coś z tą wartością 'r' przed przypisaniem do' końca'. –

Odpowiedz

15

Odpowiedź pierwotnie podana przez użytkownika ysdxon programmers:

Rzeczywiście pan wersja nie będzie wyznacznikiem algorytmu. Ponieważ nie jest używane r, nie będzie ono w ogóle oceniane.

Powinieneś być w stanie to zrobić z DeepSeq:

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

(a `deepseq` b) jest jakiś "magiczny" wyrażenie, które wymusza kompletny/rekurencyjną ocenę a przed powrotem b.

+2

Zwykły sposób, aby uchronić się przed uznaniem zasługi za pracę innych, polega na stworzeniu społeczności wiki z odpowiedziami. Wtedy odpowiedź nadal może zostać przejęta/zaakceptowana, ale nie dostaniesz kredytu :) –

+1

Nie wiedziałem tego, dzięki. Ustawiłem wspólnotowy tag wiki. Teraz dwóch przegranych może usunąć przegraną, jeśli zdarzy się, że ponownie ją przeczytają. – Giorgio

6

Chciałbym użyć rozszerzenia językowego -XBangPatterns, uważam, że dość ekspresyjny w takich sytuacjach. Więc trzeba by powiedzieć „let !r = foo inputList”, jak w:

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

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

To tylko oceni wynik dla najbardziej zewnętrznego konstruktora, tutaj wymagana jest pełna ocena. –

+1

Czy wzory uderzeniowe zapewniają całkowitą ocenę, czy też wyrażenie zostanie zredukowane do słabej formy normalnej głowy (http://stackoverflow.com/questions/6872898/haskell-what-is-weak-head-normal-form)? – Giorgio

+0

Możesz także użyć BangPatterns w foo. –