Зависит от того, что вы подразумеваете под генератором. Список генерируется лениво, и поскольку ничто иное не ссылается на него, использованные части собираются почти сразу же. Поскольку результат вышеуказанного вычисления не растет, все вычисления выполняются в постоянном пространстве. Это не предусмотрено стандартом, но так как в этом примере сложнее реализовать нестрогую семантику с различным поведением пространства (и множеством неопределенно похожих), на практике вы можете положиться на это.
Но обычно список по-прежнему генерируется как список, поэтому создается много мусора. При благоприятных обстоятельствах ghc исключает список [1 .. ]
и создает неразмещающий цикл:
result :: [Int]
result = filter odd . filter even $ [1 .. ]
(используя функции Prelude из-за лени), скомпилированный с -O2
генерирует ядро
List.result_go =
\ (x_ayH :: GHC.Prim.Int#) ->
case GHC.Prim.remInt# x_ayH 2 of _ {
__DEFAULT ->
case x_ayH of wild_Xa {
__DEFAULT -> List.result_go (GHC.Prim.+# wild_Xa 1);
9223372036854775807 -> GHC.Types.[] @ GHC.Types.Int
};
0 ->
case x_ayH of wild_Xa {
__DEFAULT -> List.result_go (GHC.Prim.+# wild_Xa 1);
9223372036854775807 -> GHC.Types.[] @ GHC.Types.Int
}
}
Простой цикл, работающий от 1 до maxBound :: Int
, ничего не производящий в пути и []
в конце.
Это почти достаточно умно, чтобы просто вернуть []
. Обратите внимание, что есть только одно деление на 2, GHC знает, что если Int
является четным, оно не может быть нечетным, поэтому проверка исключена, и ни в одной ветви не создается непустой список (т. Е. Недоступный). ветви были устранены компилятором).