fizruk

Monadic robot acting in a comonadic world…

May 10th, 2013
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# LANGUAGE FlexibleInstances, DeriveFunctor, TypeFamilies #-}
  2. module Main where
  3.  
  4. import Control.Comonad.Identity
  5. import Control.Comonad.Trans.Class
  6. import Control.Comonad.Trans.Cofree
  7. import Control.Monad.Trans.Free
  8. import Control.Monad (void)
  9.  
  10. import Control.Monad.State
  11.  
  12. import Data.Maybe (fromMaybe)
  13.  
  14. -- ==============================================================
  15. -- Helpers
  16. -- ==============================================================
  17.  
  18. -- | Try to apply a function.
  19. try :: (a -> Maybe a) -> (a -> a)
  20. try f w = fromMaybe w $ f w
  21.  
  22. -- | Unfold CofreeT structure using iteration.
  23. -- Should be in Control.Comonad.Trans.Cofree
  24. coiterT :: (Functor f, Comonad w) => (w a -> f (w a)) -> w a -> CofreeT f w a
  25. coiterT psi = CofreeT . (extend $ \w -> extract w :< fmap (coiterT psi) (psi w))
  26.  
  27. -- | Tear down through a free monad transformer using iteration.
  28. -- Should be in Control.Monad.Trans.Free
  29. iterT :: (Functor f, Monad m) => (f (m a) -> m a) -> FreeT f m a -> m a
  30. iterT psi (FreeT m) = do
  31.     val <- m
  32.     case fmap (iterT psi) val of
  33.         Pure x -> return x
  34.         Free y -> psi y
  35.  
  36. -- ==============================================================
  37.  
  38. -- | World base functor.
  39. data WorldF pos x = WorldF
  40.     { _worldPos     :: pos          -- position (cell ID)
  41.     , _worldLeft    :: (Maybe x)    -- move to the left cell, if possible
  42.     , _worldRight   :: (Maybe x)    -- move to the right cell, if possible
  43.     } deriving (Functor)
  44.  
  45. -- | World cofree comonad transformer
  46. type WorldT pos = CofreeT (WorldF pos)
  47.  
  48. -- | Interface of a comonadic world
  49. class Comonad w => ComonadWorld w where
  50.     type WPos w :: *
  51.     wPos        :: w a -> WPos w
  52.     wMoveLeft   :: w a -> Maybe (w a)
  53.     wMoveRight  :: w a -> Maybe (w a)
  54.  
  55. -- | Implementation for WorldT.
  56. instance Comonad w => ComonadWorld (CofreeT (WorldF pos) w) where
  57.     type WPos (CofreeT (WorldF pos) w) = pos
  58.     wPos       = _worldPos   . unwrap
  59.     wMoveLeft  = _worldLeft  . unwrap
  60.     wMoveRight = _worldRight . unwrap
  61.  
  62. -- | Robot base functor.
  63. data RobotF pos x
  64.     = RGetPos (pos -> x)    -- ^ get current position
  65.     | RMoveLeft  x          -- ^ move left
  66.     | RMoveRight x          -- ^ move right
  67.     deriving (Functor)
  68.  
  69. -- | Robot free monad transformer.
  70. type RobotT pos = FreeT (RobotF pos)
  71.  
  72. -- | Robot API.
  73. class Monad m => MonadRobot m where
  74.     type RPos m :: *
  75.     getPos      :: m (RPos m)
  76.     moveLeft    :: m ()
  77.     moveRight   :: m ()
  78.  
  79. -- | Implementation for RobotT.
  80. instance Monad m => MonadRobot (FreeT (RobotF pos) m) where
  81.     type RPos (FreeT (RobotF pos) m) = pos
  82.     getPos      = liftF $ RGetPos id
  83.     moveLeft    = liftF $ RMoveLeft  ()
  84.     moveRight   = liftF $ RMoveRight ()
  85.  
  86. -- | Run robot in given environment.
  87. runRobot :: (ComonadWorld w, Monad m, pos ~ WPos w) => w a -> RobotT pos m r -> m r
  88. runRobot w m = evalStateT (iterT runRobotF $ hoistFreeT lift $ m) w
  89.     where
  90.         runRobotF (RGetPos       f)    = gets   wPos >>= f
  91.         runRobotF (RMoveLeft  next) = modify (try wMoveLeft)  >> next
  92.         runRobotF (RMoveRight next) = modify (try wMoveRight) >> next
  93.  
  94. -- | Infinite world represinting Z.
  95. infiniteWorld :: (Comonad w, Num t) => w t -> WorldT t w ()
  96. infiniteWorld = void . coiterT f
  97.     where
  98.         f w = WorldF
  99.             { _worldPos   = extract w
  100.             , _worldLeft  = Just $ fmap (subtract 1) w
  101.             , _worldRight = Just $ fmap (+1) w }
  102.  
  103. -- XXX: is it possible to create abstract cell (with no neighbors) ?
  104. cell :: (ComonadWorld w) => WPos w -> w ()
  105. cell pos = undefined
  106.  
  107. -- XXX: is it reasonable and possible to combine (semi-)finite worlds?
  108. -- For instance, should that be possible:
  109. --      cell 0 |~> cell 1   -- two-cell world
  110. (<~|), (|~>) :: (ComonadWorld w) => w a -> w a -> w a
  111. (<~|) = undefined
  112. (|~>) = undefined
  113.  
  114. -- XXX: is it possible to provide an API for modifying world?
  115. -- For instance, is it possible for a robot to "build" new cells?
  116.  
  117. -- sample world
  118. world :: (Num t) => WorldT t Identity ()
  119. world = infiniteWorld $ Identity 1
  120.  
  121. -- sample robot
  122. robot :: (MonadRobot m) => m [RPos m]
  123. robot = do
  124.     moveLeft
  125.     moveLeft
  126.     x <- getPos
  127.  
  128.     moveRight
  129.     moveRight
  130.     moveRight
  131.     y <- getPos
  132.    
  133.     moveRight
  134.     z <- getPos
  135.    
  136.     return [x, y, z]
  137.  
  138. -- main
  139. main :: IO ()
  140. main = do
  141.     res <- runRobot world robot
  142.     print res
Advertisement
Add Comment
Please, Sign In to add comment