2012-04-09 12 views
18

Come posso "uccidere" un calcolo puro che richiede troppo tempo? Ho provatoTiming out pure functions

import System.Timeout 

fact 0 = 1 
fact n = n * (fact $ n - 1) 

main = do maybeNum <- timeout (10^7) $ (return . fact) 99999999 
      print maybeNum 

Tuttavia, questo non funziona. Sostituire (return . fact) 99999999 con una funzione IO "reale" come getLine e funziona come previsto.

+0

Interessante che se 'fact' diventa" reale "azione IO (' fact 0 = return 1; fact n = (n *) \ 'fmap \' (fact $ n - 1) ') quindi' timeout' funziona come previsto anche. –

+0

@MatveyAksenov: Penso che non sia tanto perché la funzione è una vera e propria azione IO, ma perché la sua ricorsione è, per mezzo di 'fmap', spostata nella monade' IO'. – leftaroundabout

+2

Se è necessario eseguire il timeout del codice arbitrario e potenzialmente dannoso, accertarsi di testare i loop non allocati molto semplici, ad es. 'Sia x = x in x' e' let x() = x() in x() '. –

risposta

20

Il punto è che

return (fact 999999999) 

restituisce immediatamente e non attiva il timeout. Restituisce un thunk che verrà valutato in seguito.

Se si forza la valutazione del valore di ritorno,

main = do maybeNum <- timeout (10^7) $ return $! fact 99999999 
      print maybeNum 

dovrebbe far scattare il timeout (se si fornisce uno stack abbastanza grande in modo che il timeout avviene prima che l'overflow dello stack).