Итак, мы имеем:
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'' <> ...))
, и в этом случае a Map.union
, которая является строгой в позвоночнике карты. Поэтому, если я создаю большую последовательность объединений, все это нужно оценить, как только я заставляю Map, который переполняет стек.
Мы хотим, чтобы профсоюзы были ранними. Нам нужен более строгий 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'')
Итак, мой вопрос: существует ли это в какой-то "стандартной" библиотеке? Если нет, почему бы и нет?