ho iniziato a lavorare su un progetto che definisce un automa cellulare come una funzione di transizione locale:Memoizing una funzione effectful
newtype Cellular g a = Cellular { delta :: (g -> a) -> a }
Ogni volta g
è un Monoid
, è possibile definire una transizione globale spostando l'attenzione prima di applicare la transizione locale. Questo ci dà la step
seguente funzione:
step :: Monoid g => Cellular g a -> (g -> a) -> (g -> a)
step cell init g = delta cell $ init . (g <>)
Ora, possiamo semplicemente eseguire l'automa utilizzando iterate
. E siamo in grado di risparmiare molto (e intendo molto: fa risparmiare letteralmente ore) di ri-calcoli da memo
izing ognuno dei passaggi:
run :: (Monoid g, Memoizable g) => Cellular g a -> (g -> a) -> [g -> a]
run cell = iterate (memo . step cell)
mio problema è che ho generalizzato Cellular
-CelluarT
in modo che sarei in grado di utilizzare gli effetti collaterali nelle regole locali (ad esempio la copia di un vicino di casa casuale):
newtype CellularT m g a = Cellular { delta :: (g -> m a) -> m a }
Tuttavia, voglio solo gli effetti per essere eseguito volta in modo che se si chiede una cella più volte quello che il suo valore è, le risposte sono tutte coerenti. memo
ci fallisce qui perché salva il calcolo efficace piuttosto che il suo risultato.
Non mi aspetto che ciò sia possibile senza utilizzare funzioni non sicure. Ho cercato di avere un andare a esso utilizzando unsafePerformIO
, un IORef
e un Map g a
per memorizzare i valori già calcolati:
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
Ma si comporta in modo imprevedibile: memoM putStrLn
sia correttamente memoized mentre memoM (\ str -> getLine)
mantiene le linee che vanno a prendere, nonostante il lo stesso argomento è passato ad esso.
Quale libreria di memo stai usando? [Memoize] (https://hackage.haskell.org/package/memoize)? – Cirdec
I tipi di dati sono equivalenti a ['Cont' e' ContT'] (https://hackage.haskell.org/package/transformers/docs/Control-Monad-Trans-Cont.html). 'type Cellular ga = Cont ag' e' type CellularT mga = ContT amg' – Cirdec