我开始在项目定义一个细胞自动机作为本地转移函数工作:Memoizing的effectful功能
newtype Cellular g a = Cellular { delta :: (g -> a) -> a }
每当g
是Monoid
,可以通过申请前将重心转移到定义一个全局转变当地的过渡。这给了我们以下step
功能:
step :: Monoid g => Cellular g a -> (g -> a) -> (g -> a)
step cell init g = delta cell $ init . (g <>)
现在,我们可以简单地通过使用iterate
运行自动机。通过memo
重新计算的定义的每一个步骤一个:我们可以节省很多(它确实可以节省时间和我意味着很多):
run :: (Monoid g, Memoizable g) => Cellular g a -> (g -> a) -> [g -> a]
run cell = iterate (memo . step cell)
我的问题是,我全身Cellular
到CelluarT
使我将能够使用本地规则副作用(例如复制一个随机的邻居):
newtype CellularT m g a = Cellular { delta :: (g -> m a) -> m a }
但是,我只希望要运行的影响一次所以,如果你问一个细胞多次什么它的价值是,答案都是一致的。 memo
使我们在这里失败,因为它节省了有效计算而不是其结果。
我不希望这可以在不使用不安全功能的情况下实现。我试着用unsafePerformIO
,一个IORef
和Map g a
存储已经计算出的值有在一搏:
memoM :: (Ord k, Monad m) => (k -> m v) -> (k -> m v)
memoM =
let ref = unsafePerformIO (newIORef empty) in
ref `seq` loopM ref
loopM :: (Monad m, Ord k) => IORef (Map k v) -> (k -> m v) -> (k -> m v)
loopM ref f k =
let m = unsafePerformIO (readIORef ref) in
case Map.lookup k m of
Just v -> return v
Nothing -> do
v <- f k
let upd = unsafePerformIO (writeIORef ref $ insert k v m)
upd `seq` return v
但不可预知的方式行为:memoM putStrLn
正确memoized同时memoM (\ str -> getLine)
保持尽管取线同样的论点被传递给它。
您使用哪个备忘录库? [memoize的](https://hackage.haskell.org/package/memoize)? – Cirdec
您的数据类型等同于['Cont'和'ContT'](https://hackage.haskell.org/package/transformers/docs/Control-Monad-Trans-Cont.html)。 'type Cellular ga = Cont ag' and'type CellularT mga = ContT amg' – Cirdec