好的,我很失望没有其他人对这个问题给出“正确”的答案,因为我知道它存在,但我无法很好地解释它。我的答案基于http://blog.sigfpe.com/2006/12/evalating-cellular-automata-is.html
首先,一个标准,即一维拉链可以是:
Data U x = U [x] x [x]
第一个元素是所有元素“左”焦点的反向列表,然后是焦点元素,然后是所有元素“右”焦点的列表。例如:
U [-1,-2,-3] 0 [1,2,3]
然后我们可以左右移动拉链。当我们跑出网格边缘时,您必须决定要做什么。原始帖子只是假设了一个无限网格,因此将角落案例留给读者作为练习。
left (U (a:as) x zs) = U as a (x:zs)
right (U as x (z:zs)) = U (x:as) z zs
现在所有看起来像容器的东西都应该是 Functor,所以:
instance Functor U where
fmap f (U a x z) = U (map f a) (f x) (map f z)
在这一点上,我真的希望其他人能够解释我将要做什么以及为什么。我将创建U
一个Control.Comonad
. 我能解释的最好的就是comonads是一种由内而外的monads。Comonads不是给你一个元素并要求你创建一个具有新值的容器(>>= :: Monad m => m a -> (a -> m b) -> m b)
,而是给你整个结构,只要求属于焦点的值:(=>>) :: Comonad w=>w a -> (w a -> b) -> w
所以使用 comonad-3.0.2 包中 Control.Comonad 的条款:
Instance Comonad U where
-- extract :: U a -> a -- called coreturn in the post
extract (U _ x _) = x
-- duplicate :: U a -> U (U a) -- called cojoin in the post
duplicate x = U (tail $ iterate left x) x (tail $ iterate right x)
duplicate 为您提供一个 Zipper of Zipper,每个 Zipper 向左或向右移动一个元素,然后是最后一个元素。这似乎是一个巨大的内存量,但 Haskell 是懒惰的,实际的内存占用非常小,如果你根本不环顾四周,整个集合的 O(n) 和 O(1) 的数量级。
但这只是一个维度。再次由于我不够聪明的原因,无法解释将其扩展到二维 id 很容易:
data U2 x = U2 (U(U x))
instance Functor U2 where
fmap f (U2 y) = U2 $ fmap (fmap f) y
instance Comonad U2 where
extract (U2 y) = extract (extract y)
duplicate (U2 y) = fmap U2 $ U2 $ roll $ role y where
iterate' f = tail . iterate f
role x = U (iterate' (fmap left) x) x (iterate' (fmap right) x)
复制功能现在创建了一个网格,每个网格都进行了适当的移动。所以
goLeft u = let (U _ (U x _ _) _) = duplicate u in x
goRight u = let (U _ (U _ _ x) _) = duplicate u in x
goUp = left . duplicate
goDown = right . duplicate
here = extract
因为 Haskell 是惰性的,所有这些都是 O(1) 函数。更有趣的是,您可以更改here
时间和内存的 O(1) 成本,并在计算中使用邻域单元。这使得实现像元game of life
胞自动机一样简单
rule (U2 (U
(U (u0:_) u1 (u2:_):_)
(U (u3:_) u4 (u5:_))
(U (u6:_) u7 (u8:_):_))) =
let n = length $ filter id [u0,u1,u2,u3,u5,u6,u7,u8] in
u4 && (n==2 || n==3) || (not u4) && n==3
-- assume u is the original graph each step is
step u = u =>> rule
除了上面的博客文章,我建议在 Google 上搜索 Comonad 以了解更多信息,特别是因为我不擅长解释这些东西。