我開始在項目定義一個細胞自動機作爲本地轉移函數工作: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