2015-09-14 19 views

risposta

18

forse non è valutato a tutti (la gioia di pigrizia) - ma se lo è, va valutata solo una volta - se volete, potete provare voi stessi con trace:

import Debug.Trace(trace) 

func n = m ++ [1] ++ m ++ [0] ++ m 
    where m = func2 n 

func2 n = trace "called..." [n] 

Ecco un esempio in GHCi:

λ> func 3 
called... 
[3,1,3,0,3] 

E qui è quella in cui si vede che non potrebbe ottenere chiamata (fino a che finalmente necessario valutarla):

λ> let v = func 4 

λ> v 
called... 
[4,1,4,0,4] 

Vedere: all'inizio non viene chiamato - solo quando si valuta infine v (per stamparlo) si ottiene la chiamata.

8

La risposta di Carsten (il valore verrà calcolato al massimo una volta) è corretta fino a quando non si disabilita la restrizione del monomorfismo. Se lo hai, allora m potrebbe avere un tipo derivato polimorfo che coinvolge una classe di tipo, e quindi m non è in realtà un valore normale, ma piuttosto una funzione che accetta un dizionario di tipo classe e produce un valore. Considera questo esempio.

{-# LANGUAGE NoMonomorphismRestriction #-} 

import Debug.Trace(trace) 

func n = m ++ [1] ++ m ++ [0] ++ m 
    where m = func2 n      -- m :: Monad t => t a (where n :: a) 

func2 n = trace "called..." (return n) -- func2 :: Monad t => a -> t a 

Poi valutare func 3 in stampe ghci

called... 
[3,1called... 
,3,0called... 
,3] 
+0

grazie - molto buon punto - In effetti non ci avevo pensato affatto. È davvero difficile dare risposte corrette su Haskell quando si tratta di dettagli come questo - di solito c'è un'estensione che rende inutilizzabile l'intuizione: * ( – Carsten

3

Per aggiungere a @ risposte di @Reid Barton di Carstan e, dipende anche se si esegue codice compilato o no, ad esempio:

{-# LANGUAGE NoMonomorphismRestriction #-} 

import Debug.Trace(trace) 

func n = m ++ [1] ++ m ++ [0] ++ m 
    where m = func2 n      -- m :: Monad t => t a (where n :: a) 

func2 n = trace "called..." (return n) 

main = let xs = func 3 :: [Int] 
     in print xs 

In ghci in esecuzione main stampe fuori called 3 volte. Una volta compilato, tuttavia, stampa solo called una volta quando si utilizza -O2. (Testato con 7.10.2.)

+0

Si sta compilando con le ottimizzazioni abilitate? Ho solo 7.10.1, ma vedo 'chiamato 'Anche stampato 3 volte quando compilato, ma certamente le ottimizzazioni possono anche influenzare questo comportamento in generale –

+0

Sì, stavo compilando con -O2. Chiarirò la risposta. – ErikR