GHC.Generics and Type Families
Posted
by
jberryman
on Stack Overflow
See other posts from Stack Overflow
or by jberryman
Published on 2012-11-19T05:49:03Z
Indexed on
2012/11/23
23:04 UTC
Read the original article
Hit count: 249
This is a question related to my module here, and is simplified a bit. It's also related to this previous question, in which I oversimplified my problem and didn't get the answer I was looking for. I hope this isn't too specific, and please change the title if you can think if a better one.
Background
My module uses a concurrent chan, split into a read side and write side. I use a special class with an associated type synonym to support polymorphic channel "joins":
{-# 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...
The code above allows us to do this kind of thing:
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
We have a recursive action called a Behavior
that we can run on the messages we pull out of the "read" end of the channel:
newtype Behavior a = Behavior (a -> IO (Behavior a))
runBehaviorOn :: Behavior a -> Messages a -> IO () -- NOT EXPORTED
This would allow us to run a Behavior (Int,Int)
on either of msgsA
or msgsB
, where in the second case both Int
s in the tuple it receives actually came through separate Mailbox
es.
This is all tied together for the user in the exposed spawn
function
spawn :: (Sources s) => Behavior (Joined s) -> IO s
...which calls newJoinedChan
and runBehaviorOn
, and returns the input Sources
.
What I'd like to do
I'd like users to be able to create a Behavior
of arbitrary product type (not just tuples) , so for instance we could run a Behavior (Pair Int Int)
on the example Messages
above. I'd like to do this with GHC.Generics
while still having a polymorphic Sources
, but can't manage to make it work.
spawn :: (Sources s, Generic (Joined s), Rep (Joined s) ~ ??) => Behavior (Joined s) -> IO s
The parts of the above example that are actually exposed in the API are the fst
of the newJoinedChan
action, and Behavior
s, so an acceptable solution can modify one or all of runBehaviorOn
or the snd
of newJoinedChan
.
I'll also be extending the API above to support sums (not implemented yet) like Behavior (Either a b)
so I hoped GHC.Generics would work for me.
Questions
Is there a way I can extend the API above to support arbitrary
Generic a=> Behavior a
?If not using GHC's Generics, are there other ways I can get the API I want with minimal end-user pain (i.e. they just have to add a deriving clause to their type)?
© Stack Overflow or respective owner