这是一个与我的模块相关的问题here,并且被简化了一点。这也与之前的问题有关,我在其中过度简化了我的问题并且没有得到我正在寻找的答案。我希望这不是太具体,如果您能想到更好的标题,请更改标题。
背景
我的模块使用并发通道,分为读取端和写入端。我使用具有关联类型同义词的特殊类来支持多态通道“加入”:
{-# LANGUAGE TypeFamilies #-}
class Sources s where
type Joined s
newJoinedChan :: IO (s, Messages (Joined s)) -- NOT EXPORTED
--output and input sides of channel:
data Messages a -- NOT EXPORTED
data Mailbox a
instance Sources (Mailbox a) where
type Joined (Mailbox a) = a
newJoinedChan = undefined
instance (Sources a, Sources b)=> Sources (a,b) where
type Joined (a,b) = (Joined a, Joined b)
newJoinedChan = undefined
-- and so on for tuples of 3,4,5...
上面的代码允许我们做这样的事情:
example = do
(mb , msgsA) <- newJoinedChan
((mb1, mb2), msgsB) <- newJoinedChan
--say that: msgsA, msgsB :: Messages (Int,Int)
--and: mb :: Mailbox (Int,Int)
-- mb1,mb2 :: Mailbox Int
我们有一个称为 a 的递归操作Behavior
,我们可以在从通道的“读取”端拉出的消息上运行它:
newtype Behavior a = Behavior (a -> IO (Behavior a))
runBehaviorOn :: Behavior a -> Messages a -> IO () -- NOT EXPORTED
这将允许我们Behavior (Int,Int)
在其中一个msgsA
or上运行 a msgsB
,在第二种情况下,Int
它接收的元组中的两个 s 实际上来自单独的Mailbox
es。
spawn
在暴露的功能中,这一切都为用户捆绑在一起
spawn :: (Sources s) => Behavior (Joined s) -> IO s
...调用newJoinedChan
and runBehaviorOn
,并返回 input Sources
。
我想做的事
我希望用户能够创建Behavior
任意产品类型(不仅仅是元组),因此例如我们可以Behavior (Pair Int Int)
在上面的示例中运行 a Messages
。我想GHC.Generics
在仍然拥有 polymorphic 的同时执行此操作Sources
,但无法使其工作。
spawn :: (Sources s, Generic (Joined s), Rep (Joined s) ~ ??) => Behavior (Joined s) -> IO s
上述示例中实际暴露在 API 中的fst
部分是newJoinedChan
操作的 of 和Behavior
s,因此可接受的解决方案可以修改一个或全部runBehaviorOn
或snd
of newJoinedChan
。
我还将扩展上面的 API 以支持 sum(尚未实现),Behavior (Either a b)
所以我希望 GHC.Generics 对我有用。
问题
有没有办法可以扩展上面的 API 以支持任意的
Generic a=> Behavior a
?如果不使用 GHC 的泛型,是否有其他方法可以让最终用户痛苦最小地获得我想要的 API(即他们只需要在他们的类型中添加一个派生子句)?例如与
Data.Data
?