Haskell, Cellular Automata and Sierpinski Rule 90

I’ve just finished writing an article for The Invariant Magazine (the annual Oxford Maths Society magazine which tends to actually get published once a decade) about cellular automata.

Whilst writing, I became a bit distracted, and decided to write some haskell to print 1D automata. After replacing most variables with single letters, and manually inlining some things, behold:

import Data.Bits
ns xs = zip3 (drop (l-1) xs') xs (tail xs') where xs' = cycle xs; l = length xs
s ru xs = map (\(l,c,r) -> if (2^(l*4 + c*2 + r) .&. ru) == 0 then 0 else 1) $ ns xs
ss = map (\c -> if c == 0 then ' ' else '#')
printAutomata :: Int -> Int -> [Int] -> IO () --one type sig needed
printAutomata n r xs = mapM_ putStrLn $ map ss $ take n $ iterate (s r) xs

Then in GHCI, let’s try to simulate Rule 90 starting with a single cell of state 1.

Prelude> :l ca.hs
[1 of 1] Compiling Main             ( ca.hs, interpreted )
Ok, modules loaded: Main.
*Main> printAutomata 20 90 $ (replicate 20 0) ++ [1] ++ (replicate 20 0)
                    #                    
                   # #                   
                  #   #                  
                 # # # #                 
                #       #                
               # #     # #               
              #   #   #   #              
             # # # # # # # #             
            #               #            
           # #             # #           
          #   #           #   #          
         # # # #         # # # #         
        #       #       #       #        
       # #     # #     # #     # #       
      #   #   #   #   #   #   #   #      
     # # # # # # # # # # # # # # # #     
    #                               #    
   # #                             # #   
  #   #                           #   #  
 # # # #                         # # # # 

Yay Sierpinski!