Итак, у нас есть:
import Control.Monad.Writer.Strict
type M a = Writer (Map Key Val) a
для некоторых Key
и Val
.
Все работает нормально, пока мы не смотрим на собранные выходные данные:
report comp = do
let (a,w) = runWriter comp
putStrLn a
Однако если мы хотим проверить w
, мы получим переполнение стека.
report comp = do
let (a,w) = runWriter comp
guard (not $ null w) $ do -- forcing w causes a stack overflow
reportOutputs w
putStrLn a
Причина, я думаю, в том, что (>>=)
для Writer
определяется как:
m >>= k = WriterT $ do
(a, w) <- runWriterT m
(b, w') <- runWriterT (k a)
return (b, w `mappend` w')
Если у меня есть большое вычисление Writer a
, оно строит длинную последовательность mappends: w <> (w' <> (w'' <> ...))
и в данном случае это Map.union
, которое является строгим в корешке карты. Поэтому, если я создам большую последовательность объединений, все это должно быть оценено, как только я форсирую карту, которая переполняет стек.
Мы хотим, чтобы союзы выполнялись раньше. Нам нужен более строгий Strict.Writer:
m >>= k = WriterT $ do
(a, w) <- runWriterT m
(b, w') <- runWriterT (k a)
let w'' = w `mappend` w'
w'' `seq` return (b, w'')
Итак, мой вопрос: существует ли это в какой-то «стандартной» библиотеке? Если нет, то почему?