Reputation: 21486
Trying to write a simplistic "model-view-controller" app in Haskell (just to learn):
Given the general types TState
TAction
TReaction
,
the key definition is that the function for change the model is
(TAction, TState) -> (TReaction, TState)
(:: TFunction_ChangeModel
)
The code to create a function :: TFunction_ChangeModel
or a function
:: TFunction_ModelAndViewCombined
is fixed and can be easily generalized (when the necessary functions are provided, see the program below).
I would like (this is the question) to get rid of having to define
dummy types like type TState = Int
with a note 'please customize'.
Thus,
can the following code be written without the first three type Txxxx =
?
(Note: any suggestion and criticism is welcome).
-- just to make this compile
type TState = Int
type TAction = Char
type TReaction = Double
-- aply an action to an state gives a new state
type TFunction_ChangeState = TState -> TAction -> TState
-- when a state is entered, a reaction is produced
type TFunction_WhatReaction = TState -> TReaction
-- the model is a function from an action and a state into a new state and a reaction
type TFunction_ChangeModel = (TAction, TState) -> (TReaction, TState)
-- given the functions for changing state and finding out what reaction is produced
-- it is straightforward to define the function for change a model
createModelChangeFunction :: TFunction_ChangeState -> TFunction_WhatReaction -> TFunction_ChangeModel
createModelChangeFunction changeState whatReaction = \(ac, st) -> let
ns = changeState st ac
re = whatReaction ns
in (re, ns)
-- show a view of a transition to a new state and the associated reaction
type TFunction_View = (TReaction, TState) -> IO ()
-- change model and view functions can be easily combined
type TFunction_ModelAndViewCombined = (TAction, TState) -> IO TState
combineModelAndView :: TFunction_ChangeModel -> TFunction_View -> TFunction_ModelAndViewCombined
combineModelAndView change view = \(a, s) -> do
let (r, s') = change (a, s)
view (r, s')
return s'
--
type TFunction_ControllerLoop = TState -> TFunction_ModelAndViewCombined -> IO TState
--
main = do
print "hi"
Upvotes: 0
Views: 90
Reputation: 21486
I've managed to refactor the code to a simpler, readable and usable version using multi param typeclasses in this answer
Upvotes: 0
Reputation: 52300
not sure what you are trying to do here - but if you just want to parametrize over the state, action, reaction... then you can lift those as type-paramters in your types:
-- aply an action to an state gives a new state
type TFunction_ChangeState tState tAction = tState -> tAction -> tState
-- when a state is entered, a reaction is produced
type TFunction_WhatReaction tState tReaction = tState -> tReaction
-- the model is a function from an action and a state into a new state and a reaction
type TFunction_ChangeModel tState tAction tReaction = (tAction, tState) -> (tReaction, tState)
-- given the functions for changing state and finding out what reaction is produced
-- it is straightforward to define the function for change a model
createModelChangeFunction :: TFunction_ChangeState tState tAction
-> TFunction_WhatReaction tState tReaction
-> TFunction_ChangeModel tState tAction tReaction
createModelChangeFunction changeState whatReaction = \(ac, st) -> let
ns = changeState st ac
re = whatReaction ns
in (re, ns)
-- show a view of a transition to a new state and the associated reaction
type TFunction_View tState tReaction = (tReaction, tState) -> IO ()
-- change model and view functions can be easily combined
type TFunction_ModelAndViewCombined tState tAction = (tAction, tState) -> IO tState
combineModelAndView :: TFunction_ChangeModel tState tAction tReaction
-> TFunction_View tState tReaction
-> TFunction_ModelAndViewCombined tState tAction
combineModelAndView change view = \(a, s) -> do
let (r, s') = change (a, s)
view (r, s')
return s'
--
type TFunction_ControllerLoop tState tAction =
tState -> TFunction_ModelAndViewCombined tState tAction -> IO tState
I'm not saying that this is beautiful ;)
Upvotes: 2