Я начал работать над проектом, определяющим клеточный автомат как локальную функцию перехода:
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
правильно запоминается, в то время как memoM (\ str -> getLine)
продолжает извлекать строки, несмотря на то, что ему передается тот же аргумент.
Cont
иContT
.type Cellular g a = Cont a g
иtype CellularT m g a = ContT a m g
- person Cirdec   schedule 11.09.2015