1
- . , , . , Identity , instance Monad a a, - Monad. , , .
2
Data.Dynamic, , , , . , Haskell, , , Data.Dynamic. , , , .
3
, , . , , , Creature. , numParrots , .
4
. , , " ", , (, ParrotWorld).
, Data.Typeable. , , , .
{-# LANGUAGE DeriveDataTypeable,
ImpredicativeTypes,
NoMonomorphismRestriction,
RankNTypes,
ScopedTypeVariables #-}
module Test where
import Data.Typeable
type Message = String
class Typeable α => Creature α where
processInput :: α -> Message -> Message
-- box a creature
type BoxedC = (Message -> Message, Typeable β => Maybe β)
boxC :: Creature α => α -> BoxedC
boxC x = (processInput x, cast x)
class World α where
-- from your description, I'd not have Creature as part of this.
processAction :: α -> Message -> α
getCreatures :: α -> [BoxedC]
data Parrot = Parrot { parrotMessage :: String } deriving Typeable
data Lizard = Lizard { lizardMessage :: String } deriving Typeable
instance Creature Parrot where processInput p _ = (parrotMessage p)
instance Creature Lizard where processInput l _ = (lizardMessage l)
-- NOTE: Keep it simple and use a single World instance
-- (i.e. no typeclass) unless you need it.
data BaseWorld = BaseWorld { creatureList :: [BoxedC] }
instance World BaseWorld where
processAction w _ = w
getCreatures = creatureList
w = BaseWorld [boxC $ Parrot "parrot1", boxC $ Lizard "Lizard1"]
numParrots :: [BoxedC] -> Int
numParrots lst = foldl (+) 0 (map (go . snd) lst) where
go :: (forall β. Typeable β => Maybe β) -> Int
go (Just x :: Maybe Parrot) = 1
go _ = 0
test = numParrots (getCreatures w)
: , . , , . , , , , , , , . , . ,
bind_creature :: Creature -> World -> World
, World , ,
data World = World { nextWorld :: World }
, w = World w. ,
transformWorld :: Creature -> World -> World
bind_creature ,
bind_creature c w = World { nextWorld = transformWorld c (nextWorld w) }
, .