0

I trying to develop heavy network application and i use ProtoBuf for description network messages.

This is simplified version of my code. It doesn't work because of monomorphism restriction.

class Message a where
  pack :: a -> ByteString
  unpack :: ByteString -> Maybe a

data HelloMsg = HelloMsg deriving Show
instance Message HelloMsg -- ... using protobuf

data PingMsg = PingMsg deriving Show
instance Message PingMsg -- ... using protobuf

data PongMsg = PongMsg deriving Show
instance Message PongMsg -- ... using protobuf
-- and more 50 another...

data MsgType = Hello | Ping | Pong -- | and more 50 another ...
data CommonMsg a = CommonMsg MsgType a deriving Show

instance (Message a) => CommonMsg a where
  pack (CommonMsg type msg) = concat [packType type, pack msg]
  unpack bin = let (type, rest) = unpackType bin in CommonMsg type <$> unpack rest
  -- here i need unpack message depend on type

receiver :: Chan (CommonMsg a) -> IO ()
receiver out = void $ forkIO $ forever $ do
  msg <- unpack <$> getCommonMsgFromNet
  writeChan out

main = do
  input <- newChan
  receiver input
  forver $ do
    msg <- readChan input
    putStrLn $ show msg

What workarounds exist? Link to the project with a similar architecture is highly desirable

UPDATE: Rephrase my question - i need polymorphic approach deserialize ByteString to Message depend on message type.

Ilya Rezvov
  • 914
  • 5
  • 13
  • 1
    You don't want to use `-XNoMonomorphismRestriction`? – DiegoNolan Nov 21 '13 at 20:06
  • @DiegoNolan which downside NoMonomorphismRestriction have in this case? I try choose best solution – Ilya Rezvov Nov 21 '13 at 20:09
  • 1
    I don't think there is really one. The only argument against I've seen is the possibility of computing a function twice. You can read [this](https://ghc.haskell.org/trac/haskell-prime/wiki/NoMonomorphismRestriction) and [this](http://www.haskell.org/haskellwiki/Monomorphism_restriction). Possibly wait for someone more experienced to come along. Also a type class may not be needed here. You could probabyl just do `data Message a = Message {pack :: a => ByteString, unpack :: ByteString => a}` – DiegoNolan Nov 21 '13 at 20:29
  • Agree with DiegoNolan. The monomorphism restriction is pretty much complete rubbish; if you properly give all functions signatures you should never be dependent on it. – leftaroundabout Nov 21 '13 at 20:30
  • Did you mean `writeChan out msg`? That could lead to `unpack` being ambiguously typed. Also, why are there two `forever`s? The second is redundant. – J. Abrahamson Nov 21 '13 at 22:55
  • @J.Abrahamson with double `forverver` is my mistake, i fix it. I have message type value, that uniquely identifies the Message instance. But i don't know how to tell it to compiler. – Ilya Rezvov Nov 22 '13 at 07:19
  • @IlyaRezvov By the code you pasted here, there's no way for Haskell to link the type signature of `receiver` to the type signature of `unpack`---the message needs to be placed into the channel so that Haskell knows to unify the output of `unpack` with `CommonMsg`. – J. Abrahamson Nov 22 '13 at 15:52

0 Answers0