我目前正在研究Haskell中的游戏引擎,现在我正在尝试在此引擎的子系统之间实现消息传递系统(我正在使用Publisher-Subscriber模式)。您可以在here on my github profile查看整个代码。我实施了一个"参与者"参与我的Messaging系统的所有数据类型的类型类,如下所示:
class (Show m, Message m) => Participant prt m where
-- | Function to get the lsit of subscribers from the participant
partSubscribers
:: prt
-- ^ the participant
-> forall us. Affection us [(m -> Affection us ())]
-- ^ List of Subscriber functions
-- | Subscribe to the 'Participant''s events
partSubscribe
:: prt
-- ^ The 'Participant' to subscribe to
-> (forall us. m -> Affection us ())
-- ^ What to do in case of a 'Message'
-- (Subscriber function)
-> Affection us UUID
-- ^ 'UUID' of the registered subscriber Function
-- | Unsubscribe a Subscriber function from Participant
partUnSubscribe
:: prt -- ^ The 'Participant' to unsubscribe from
-> UUID -- ^ The subscriber function's 'UUID'
-> Affection us ()
-- | Get the 'Participant' to emit a 'Message' on all of its subscribers
partEmit
:: prt -- ^ The 'Participant'
-> m -- ^ The 'Message' to emit
-> Affection us ()
partEmit p m = do
liftIO $ logIO Debug $ "Emitting message: " ++ show m
l <- partSubscribers p
mapM_ ($ m) l
这个类型类的具体实现看起来像这样。我正在使用套餐stm
:
data AffectionWindow us = AffectionWindow
{ windowSubscribers
:: forall us. TVar [(UUID, WindowMessage -> Affection us ())]
}
instance Participant (AffectionWindow us) WindowMessage where
partSubscribe p funct = do
uuid <- genUUID
liftIO $ atomically $ modifyTVar' (windowSubscribers p) ((uuid, funct) :)
return uuid
partUnSubscribe p uuid =
liftIO $ atomically $ modifyTVar' (windowSubscribers p)
(filter (\(u, _) -> u /= uuid))
partSubscribers p = do
subTups <- liftIO $ readTVarIO $ windowSubscribers p
return $ map snd subTups
这段代码编译得很好,但是当我尝试在最小的例子中使用它时,它无法编译。它失败的代码如下所示:
load :: IO StateData
load = do
empty1 <- newTVarIO []
-- ([] :: [(UUID, WindowMessage -> Affection StateData ())])
empty2 <- newTVarIO []
-- ([] :: [(UUID, MouseMessage -> Affection StateData ())])
empty3 <- newTVarIO []
-- ([] :: [(UUID, KeyboardMessage -> Affection StateData ())])
return $ StateData $ Subsystems
(AffectionWindow empty1)
(AffectionMouse empty2)
(AffectionKeyboard empty3)
,错误信息为:
examples/example00.hs:43:22: error:
• Couldn't match type ‘a0’
with ‘(UUID, WindowMessage -> Affection us1 ())’
because type variable ‘us1’ would escape its scope
This (rigid, skolem) type variable is bound by
a type expected by the context:
forall us1. TVar [(UUID, WindowMessage -> Affection us1 ())]
at examples/example00.hs:43:6-27
Expected type: TVar [(UUID, WindowMessage -> Affection us1 ())]
Actual type: TVar [a0]
• In the first argument of ‘AffectionWindow’, namely ‘empty1’
In the first argument of ‘Subsystems’, namely
‘(AffectionWindow empty1)’
In the second argument of ‘($)’, namely
‘Subsystems
(AffectionWindow empty1)
(AffectionMouse empty2)
(AffectionKeyboard empty3)’
• Relevant bindings include
empty1 :: TVar [a0] (bound at examples/example00.hs:39:3)
|
43 | (AffectionWindow empty1)
| ^^^^^^
我从来没有遇到过这样的错误,而且我的智慧结束了。 希望有人在这里知道解决方案。
谢谢你的时间!