Используйте deepSeq
.Он используется так же, как seq
.Вы бы включили это следующим образом:
myForkedProcess :: IORef [[Color]] -> IO ()
myForkedProcess ref = do let colors = takesAgesToRun
deepSeq colors $ writeIORef ref colors
Это заставит «цвета» полностью оцениваться перед вызовом «writeIORef».
Для того, чтобы это работало, вам понадобитсяNFData
экземпляр для Color
.Как именно это написать, зависит от определения цвета, но вот два примера:
-- just for reference
data Color = Color Double Double Double
instance NFData Color where
rnf (Color r g b) = r `seq` g `seq` b `seq` ()
-- closer to the likely actual implementation for Color
data Color2 = Color2 !Double !Double !Double
instance NFData Color2 where
-- the default implementation is fine
Для экземпляра Color
необходимо убедиться, что все компоненты цвета полностью оценены [1]всякий раз, когда цвет.Это то, что делают seq
.Мы можем использовать seq
вместо deepSeq
здесь, потому что мы знаем, что каждый компонент является Double
, поэтому полностью вычисляется с помощью seq.Если бы компонент был более сложным типом данных, то нам пришлось бы использовать deepSeq
при записи экземпляра NFData.
В Color2
это немного проще.Из-за паттернов взрыва мы знаем, что компоненты полностью оцениваются, когда Color2
.Это означает, что мы можем использовать реализацию по умолчанию, которая оценивает Color2
в слабую нормальную форму головы, которая из-за шаблонов взрыва полностью оценивается.
rnf
в основном полезна при использовании в сочетании с Control.Parallel.Strategies.Вот текущее определение deepSeq
deepseq :: NFData a => a -> b -> b
deepseq a b = rnf a `seq` b
Все, что делает Deepseq, вызывает rnf
и гарантирует, что его output () оценен.Это действительно единственный способ использовать rnf
напрямую.
[1] Haskell предоставляет только два основных способа оценки материала: сопоставление с образцом и seq
.Все остальное построено на одном или обоих из них.Для экземпляра NFData Color Color
сначала оценивается в WHNF путем сопоставления с шаблоном с помощью конструктора Color
, затем компоненты оцениваются с помощью seq.
Конечно, есть и третий, узкоспециализированный способоценивать вещи: т.е. будет выполняться функция main :: IO ()
для оценки ()
.