a one dimensional cellular automata, using comonads
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

68 строки
1.7KB

  1. {-# LANGUAGE DeriveGeneric #-}
  2. module Spaces.Space1 where
  3. import Comonad
  4. import Control.DeepSeq
  5. import GHC.Generics
  6. -- a locally focussed space
  7. data Space t = Space [t] t [t]
  8. deriving (Generic, Generic1, Show)
  9. -- allowing strict evaluation of a space
  10. instance NFData a => NFData (Space a)
  11. instance NFData1 Space
  12. -- spaces are also functors
  13. instance Functor Space where
  14. fmap f (Space l c r) = Space (map f l) (f c) (map f r)
  15. -- moving a space focus right
  16. right :: Space t -> Maybe (Space t)
  17. right (Space _ _ []) = Nothing
  18. right (Space l c (r:rs)) = Just $ Space (c:l) r rs
  19. -- moving a space's focus left
  20. left :: Space t -> Maybe (Space t)
  21. left (Space [] _ _) = Nothing
  22. left (Space (l:ls) c r) = Just $ Space ls l (c:r)
  23. -- iterate until we reach an edge
  24. finterate :: (a -> Maybe a) -> a -> [a]
  25. finterate f x = case (f x) of
  26. Nothing -> []
  27. Just y -> y : finterate f y
  28. -- our space is a comonad
  29. instance Comonad Space where
  30. -- duplicate creats a meta space
  31. duplicate w =
  32. Space (finterate left w)
  33. w
  34. (finterate right w)
  35. -- extract simply returns the focussed element
  36. extract (Space _ c _) = c
  37. -- clamp an infinite space to a finite space
  38. -- relative to center
  39. clampRel :: Int -> Int -> Space t -> Space t
  40. clampRel x y (Space l m r) = Space (take x l) m (take y r)
  41. -- as above, but with a set width
  42. -- if the width is even, we need to take one less from the left
  43. clamp :: Int -> Space t -> Space t
  44. clamp w (Space l m r) = Space (take ln l) m (take h r)
  45. where
  46. h = w `div` 2
  47. ln = h - (if even w then 1 else 0)
  48. -- materialises a space, will hang if infinite
  49. mat :: Space t -> [t]
  50. mat (Space l m r) = (reverse l) ++ (m:r)
  51. -- as above, but clamps to a given size first
  52. matn :: Int -> Space t -> [t]
  53. matn n = mat . (clamp n)