我正在写一个游戏库。我让它与实例的层次结构一起工作
class Animation a where
event :: a -> Event -> Writer [Event] a
paint :: a -> IO ()
这里event
处理一个事件并可能发出新事件供其父级查看(例如,出口Button
可以等待MouseClickEvent
并发出 a CloseEvent
)并进行paint
绘制。我的通用用例是
--a user defined Animation, say a button
data MyChild = MyChild
instance Animation Child where
... anything
--a library defined Animation which is a composition of other animations
data LibWrapper = LibWrapper (Event -> Writer [Event] LibWrapper) (IO ())
mkWrapper :: (Animation a) => a -> LibWrapper
mkWrapper a = LibWrapper (\ev -> mkWrapper <$> event a ev) (paint a)
instance Animation LibWrapper where
event (LibWrapper e _) = e
paint (LibWrapper _ p) = p
--a user defined Animation for which the 'event' and 'paint' will be called
data MyRoot = MyRoot LibWrapper
instance Animation MyRoot where
event (MyRoot a) ev = MyRoot <$> event a ev
paint (MyRoot a) = paint a
game = MyRoot (mkWrapper Child)
现在我想允许自定义事件。那是,
class Animation a e where
event :: a -> e -> Writer [e] a
paint :: a -> IO ()
问题是我不能让LibWrapper
( instance Animation LibWrapper anyevent
) 包含更受限制的MyChild
( instance Animation MyChild MyEvent
)。我尝试参数化LibWrapper
并拥有,instance Animation (LibWrapper event) event
但 Haskell 似乎认为这两次出现event
无关,我不知道该怎么做。
我也考虑过
class Animation a where
event :: a e -> e -> Writer [e] (a e)
paint :: a e -> IO ()
然后它LibWrapper MyEvent
包含 a MyChild MyEvent
,这很好。但我没有办法再定义instance MyChild MyEvent
了,不是吗?
但是,我更愿意MyEvent
指定类型MyRoot
,如果存在将其作为参数传递给我的库模块的方法,那也是可以接受的。
编辑
就像我发布问题一样,我想尝试
class Animation a e where
event :: a e -> e -> Writer [e] (a e)
paint :: a e -> IO ()
...以防万一。当然,它奏效了。我还是不太明白这里发生的类型魔法。我会很感激解释。