Given its body functions, create an instance of a type class (or workaround)
I would like to have a State Monad, where I keep a list of modes.
data State = S {
modes :: [Mode]
}
However, I have two requirements:
Here is how I tried to convince GHC:
Attempt 1 , with a data type
data Mode a = Mode {
complF :: String -> IO [String]
action :: State -> String -> X a
}
data State a = S {
modes :: [Mode a]
}
initState :: (String -> IO [String]) -> (State -> String -> X a) -> State a
initState c a = {
modes = [buildMode c a]
}
buildMode :: (String -> IO [String]) -> (State -> String -> X a) -> Mode a
buildMode c a = {
complF = c
, action = a
}
Good.. however, this is not useful for me, since every mode has to be of type Mode a
inside a State a
. Meaning that no Mode String
and Mode ()
can co-exist within a State.
Attempt 2 :, type class
class Mode a where
complF :: String -> IO [String]
action :: State -> String -> X a
data State = S {
modes :: (Mode a) => [a]
}
But, now I don't know how to build a mode in run time given complF
and action
. It seems that instances of type classes must be defined at compile time.
instance Mode DefaultMode where
complF :: ..
action :: ..
Is there a workaround?
If modes support a fixed API, you can use an existential type to hide their representation type. Eg
data State = S {
modes :: forall a . ModeLike a => [Mode a]
}
and then implement a class ModeLike
that has only those operations supported by Mode
types. Your 2nd attempt is close to this.
Since type class instances are open, you add new instances without changing your code.
If you have, however, a fully dynamic system -- ie you cannot enumerate the types that will be possible modes - you will have to use a dynamic type as one of the instances.
链接地址: http://www.djcxy.com/p/86098.html