Dlaczego funkcja sekwencji Haskella nie może być leniwa lub dlaczego rekurencyjne funkcje monadyczne nie mogą być leniwe

Z pytaniemWyświetlanie całej zawartości katalogu według pierwszego rzędu skutkuje niską wydajnościąDowiedziałem się, że niska wydajność wynika z dziwnego zachowania rekurencyjnych funkcji monad.

Próbować

sequence $ map return [1..]::[[Int]]
sequence $ map return [1..]::Maybe [Int]

a ghci popadnie w niekończące się obliczenia.

Jeśli przepisamy funkcję sekwencji w bardziej czytelnej formie, jak poniżej:

sequence' []     = return []
sequence' (m:ms) = do {x<-m; xs<-sequence' ms; return (x:xs)}

i próbuj:

sequence' $ map return [1..]::[[Int]]
sequence' $ map return [1..]::Maybe [Int]

mamy taką samą sytuację, nieskończoną pętlę.

Wypróbuj skończoną listę

sequence' $ map return [1..]::Maybe [Int]

wyłoni oczekiwany wynikJust [1,2,3,4..] po długim oczekiwaniu.

Z tego, co próbowaliśmy, możemy dojść do wniosku, że chociaż definicja sekwencji „wydaje się być leniwa, jest ścisła i musi zawierać wszystkie liczby, zanim wynik sekwencji” może zostać wydrukowany.

Nie tylko sekwencja, jeśli zdefiniujemy funkcję

iterateM:: Monad m => (a -> m a) -> a -> m [a]
iterateM f x = (f x) >>= iterateM0 f >>= return.(x:)

i próbuj

iterateM (>>=(+1)) 0

wtedy niekończące się obliczenia.

Jak wszyscy wiemy, nie-monadyczna iteracja jest zdefiniowana tak samo jak powyższa iteracjaM, ale dlaczego iteracja jest leniwa i iteracjaM jest ścisła. Jak widać z powyższego, zarówno iteracja M, jak i sekwencja są rekurencyjnymi funkcjami monadycznymi. Czy jest coś dziwnego w rekurencyjnych funkcjach monadycznych

questionAnswers(3)

yourAnswerToTheQuestion