Probabilmente la tua confusione deriva dal fatto che sei abituato a una valutazione entusiasta, mentre Haskell usa la valutazione pigra.
Ad esempio, se si dovesse utilizzare la definizione
repeat' x = x : repeat' x
per valutare l'espressione repeat' 10
avidamente, allora otterresti
repeat' 10 ==>
10 : repeat' 10 ==>
10 : 10 : repeat' 10 ==>
10 : 10 : 10 : repeat' 10 ==>
...
e questo si fermerebbe per sempre.
Con la valutazione pigra è diverso. Se hai l'espressione repeat' 10
in un determinato contesto, questo non viene valutato finché non è richiesto il risultato di repeat' 10
.
Non appena prendi i valori dalla lista, i passaggi precedenti sono eseguiti, ma solo quanti di loro vengono eseguiti come richiesto.
Quindi, in Haskell applicare la tua funzione ad un certo valore non crea una struttura di dati infinita che è completamente caricata in memoria ad un certo punto nel tempo: questo è impossibile perché c'è solo una quantità limitata di memoria e un calcolo che termina può richiede solo una quantità limitata di tempo Crea piuttosto un programma dal quale puoi estrarre qualsiasi numero finito di elementi, ad esempio qualsiasi prefisso finito della lista infinita.
Si noti che il prefisso finito non è rappresentato come un elenco semplice
10 : 10 : 10 : []
ma come un termine come
10 : 10 : 10 : repeat' 10
Quindi, supponiamo di voler calcolare con un elenco finito, ad es. take 2 [1, 2, 3]
:
take 2 (1 : 2 : 3 : []) ==>
1 : take 1 (2 : 3 : []) ==>
1 : 2 : take 0 (3 : []) ==>
1 : 2 : []
Ora, lo stesso ma con il tuo elenco infinito:
take 2 (repeat' 10) ==> -- repeat' x = x : repeat' x
take 2 (10 : repeat' 10) ==> -- take n (x : xs) = x : take (n - 1) xs
10 : take 1 (repeat' 10) ==> -- repeat' x = x : repeat' x
10 : take 1 (10 : repeat' 10) ==> -- take n (x : xs) = x : take (n - 1) xs
10 : 10 : take 0 (repeat' 10) ==> -- take 0 _ = []
10 : 10 : []