Ben recently tried this and I wanted to see if I could do it my way

I’ve seen this done (Bartosz?) before but I tried to do it without looking anything up.

The comonad is an interesting pattern to use. It automates the translation invariant nature off the cellular automata. This would also be useful for translationally invariant PDEs like the simple wave equation or others.

I used the laziness of Haskell to start with an infinite plane of zeros. Of course if you ever want to look at it, you need to pick a finite slice at the end using dtake

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-} import Control.Comonad import Data.Bits {- example usage This pushes forward the initial state forward by 1 time step according to rule 30 let s1 = extend (cellRule 30) initState Comments: My rule is coming out right-left swapped compared to Wolfram? I should probably custom implement Show, since the left list is printed out of order -} -- a two sided list with focus --alternatively may be preferable to not use those inner lists and instead make more recursive. --I have implicitly assume that these lists are infinite, which is bad practice. Sorry. data DoubleList a = DList [a] a [a] deriving (Functor, Show) data CellValue = Alive | Dead deriving Show lshift (DList (l:ls) x rs) = DList ls l (x:rs) rshift (DList ls x (r:rs)) = DList (x:ls) r rs toList (DList ls x rs) = ls ++ [x] ++ rs lList (DList ls _ _) = ls rList (DList _ _ rs) = rs -- truncates the Dlist to 2n + 1 dtake n (DList ls x rs) = DList (take n ls) x (take n rs) --kind of ugly --f is a function that uses the context -- patches together the result out of doing it on shifted Dlists instance Comonad DoubleList where extract (DList _ x _) = x extend f z = DList (l:ls) (f z) (r:rs) where lDList = extend f (lshift z) ls = lList lDList l = extract lDList rDList = extend f (rshift z) rs = rList rDList r = extract rDList cellToNum Alive = 1 cellToNum Dead = 0 cellNeighborToNum x y z = x' + 2 * y' + 4 * z' where x' = cellToNum x y' = cellToNum y z' = cellToNum z cellRule :: Int -> (DoubleList CellValue -> CellValue ) cellRule rulenum (DList (l:ls) x (r:rs)) = if testBit rulenum y then Alive else Dead where y = cellNeighborToNum l x r :: Int initState = DList deads Alive deads where deads = repeat Dead |