我想在Haskell中编写以下数据结构:
Renderable a => [a] -- [ClassOne, ClassTwo, ClassThree]
其中Renderable
是类型类
class Renderable a ...
并且所有具体类都实现了类型类
instance Renderable ClassOne ...
instance Renderable ClassTwo ...
instance Renderable ClassThree ...
这方面的一个具体例子是为游戏引擎编写World
类。
data World a = World {
-- ...
wEntities :: [a]
}
然而,这迫使一个同质的列表。我可以写
{-# ExistentialQuantification #-}
data World = forall r. Renderable r => World {
-- ...
wEntities :: [r]
}
但我收到了错误
Record updates for insufficiently polymorphic fields
写作时
world { wEntities = fmap fn (wEntities world) }
是否有任何替代方案允许基于类型类的异构收集?
答案 0 :(得分:2)
如果你真的需要一个Renderable
的列表,你可以使用存在。
class Renderable r where
render :: r -> IO () -- dummy example
data R where
R :: Renderable r => r -> R
-- or, if you prefer non-GADT syntax,
-- data R = forall r. Renderable r => r -> R
foo :: [R] -> IO ()
foo [] = return ()
foo (R r : rs) = render r >> foo rs
但是,请注意,因为可能不需要这种额外的复杂性,有时会导致antipattern。