我想有一个State Monad,我会保留一份模式列表。
data State = S {
modes :: [Mode]
}
但是,我有两个要求:
以下是我试图说服GHC的方式:
尝试1 ,数据类型
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
}
好......但是,这对我没用,因为每个模式都必须在Mode a
内的State a
类型。这意味着任何Mode String
和Mode ()
都不能在一个国家内共存。
尝试2 :,输入class
class Mode a where
complF :: String -> IO [String]
action :: State -> String -> X a
data State = S {
modes :: (Mode a) => [a]
}
但是,现在我不知道如何在complF
和action
的运行时间内构建模式。似乎必须在编译时定义类型类的实例。
instance Mode DefaultMode where
complF :: ..
action :: ..
有解决方法吗?
答案 0 :(得分:4)
如果模式支持固定API,则可以使用existential type隐藏其表示类型。 E.g。
data State = S {
modes :: forall a . ModeLike a => [Mode a]
}
然后实现只有ModeLike
类型支持的操作的类Mode
。你的第二次尝试接近于此。
由于类型类实例已打开,因此您无需更改代码即可添加新实例。
但是,如果您有一个完全动态的系统 - 即您无法枚举可能的模式类型 - 您将不得不使用动态类型作为其中一个实例。