module coffeemachine import StdEnv import StdIO import StdGEC /**************************************************************************************** * * An example function needs to be of type (PSt Void) -> (PSt Void). * *****************************************************************************************/ Start :: *World -> *World Start world = startIO MDI Void coffeemachine [ProcessClose closeProcess] world /***************************************************************************************** * * The Client-Coffee Machine model: * ******************************************************************************************/ :: Client // Client actions: = InsertCoin // insert a coin | Get Product // ask for product | AddBeans // add beans in machine | EmptyTrash // empty bean trash of machine | Idle // does nothing :: Machine // CoffeeMachine: = { money :: Int // nr of coins (maxCoins) , beans :: Int // amount of beans (maxBeans) , trash :: Int // amount of bean-trash (maxTrash) , out :: Output // output of machine } :: Product = Coffee | Capuccino | Espresso :: Msg :== String // Errors or customer-friendly information :: Output = Message Msg | Prod Product maxCoins :== 10 // max. number of coins in machine maxBeans :== 20 // max. amount of coffeebeans in machine maxTrash :== 5 // max. amount of coffeetrash in machine beanBag :== 10 // unit of bean refill // The number of coins that a product costs cost :: Product -> Int cost Coffee = 1 cost Capuccino = 2 cost Espresso = 3 // The number of beans that a product costs beancost :: Product -> Int beancost Coffee = 2 beancost Capuccino = 1 beancost Espresso = 1 // Amount of trash generated by product ptrash :: Product -> Int ptrash _ = 1 // dataModelFun is the self-correcting function on the model data of the Client-Coffee Machine: dataModelFun :: (Client,Machine) -> (Client,Machine) dataModelFun (InsertCoin, m=:{money}) | money >= maxCoins = (Idle, { m & out = Message "Coin not accepted." } ) | otherwise = (Idle, { m & money = money+1, out = Message "Thank you." } ) dataModelFun (EmptyTrash, m) = (Idle, { m & trash = 0, out = Message "Trash emptied." } ) dataModelFun (AddBeans, m=:{beans}) | beans > maxBeans-beanBag = (Idle, { m & out = Message "Too many beans." } ) | otherwise = (Idle, { m & beans = beans+beanBag, out = Message "Beans refilled." } ) dataModelFun (Get p,m=:{money,beans,trash}) | beans < beancost p = (Idle, { m & out = Message "Not enough beans." } ) | money < cost p = (Idle, { m & out = Message "Not enough coins." } ) | trash + ptrash p > maxTrash = (Idle, { m & out = Message "Trash full." } ) | otherwise = (Idle, { m & out = Prod p , beans = beans - beancost p , money = money - cost p , trash = trash + ptrash p } ) dataModelFun (_,m) = (Idle,m) derive gGEC Client, Machine, Product, Output instance toString Output where toString (Message s) = s toString (Prod Coffee) = "Coffee" toString (Prod Capuccino) = "Capuccino" toString (Prod Espresso) = "Espresso" isPressed :: Button -> Bool isPressed (Button _ _) = False isPressed Pressed = True derive ggen Mode, Button, Machine, Output, Product coffeemachine = startCircuit (feedback (edit "Coffee" >>> arr updCoffee)) (toViewModel (Idle,initCoffee)) where updCoffee = toViewModel o dataModelFun o fromViewModel // toViewModel transform the data model to the view model of the Client-Coffee Machine: toViewModel (_, m=:{money,beans,trash,out}) = hidAGEC m <|> Display "money " <-> Display (toString money +++ " ") <-> Button 80 "Insert coin" <|> Display "beans " <-> Display (toString beans +++ " ") <-> Button 80 "Add beans" <|> Display "trash " <-> Display (toString trash +++ " ") <-> Button 80 "Empty trash" <|> Button (2*defCellWidth/3) "Coffee" <-> Button (2*defCellWidth/3) "Capuccino" <-> Button (2*defCellWidth/3) "Espresso" <|> Display (toString out +++ ". ") // fromViewModel transform the view model to the data model of the Client-Coffee Machine: fromViewModel (m <|> _ <-> _ <-> btnInsertCoin <|> _ <-> _ <-> btnAddBeans <|> _ <-> _ <-> btnEmptyTrash <|> btnCoffee <-> btnCapuccino <-> btnEspresso <|> _) = (client,^^m) where client = if (isPressed btnInsertCoin) InsertCoin (if (isPressed btnAddBeans) AddBeans (if (isPressed btnEmptyTrash) EmptyTrash (if (isPressed btnCoffee) (Get Coffee) (if (isPressed btnCapuccino) (Get Capuccino) (if (isPressed btnEspresso) (Get Espresso) Idle))))) initCoffee = {money=0,beans=6,trash=0,out=Message "Welcome."}