Skip to content

Using IndexMonad to improve typed-protocols #25

Open
@sdzx-1

Description

Is your feature request related to a problem? Please describe.

Peer is essentially a McBride style indexed monad.
With a slight modification to Peer, we can use do syntax to describe Peer.

new Peer implement:

https://github.com/sdzx-1/typed-protocols-i/blob/685fb27ec0b57bab508874127c578ead22807a28/src/Network/TypedProtocol/Core.hs#L67

use do syntax to describe Peer:
https://github.com/sdzx-1/typed-protocols-i/blob/685fb27ec0b57bab508874127c578ead22807a28/test/Network/Core.hs#L46

pingPongClientPeer :: Has (State Int) sig m 
                   => Peer PingPong AsClient m (At () StDone) StIdle
pingPongClientPeer = I.do
    -- ghc bug: https://gitlab.haskell.org/ghc/ghc/-/issues/22788 
    -- we can't use this: 
    -- i <- effect (get @Int) 
    -- if i > 10 
    --   then  ...
    --   else ...
    --
    effect (get @Int) I.>>= 
      \(At i ) ->
         if i > 10 
          then I.do
            yield (ClientAgency TokIdle) MsgDone
            done TokDone ()
          else I.do
            yield (ClientAgency TokIdle) MsgPing 
            effect $ modify @Int (+1)
            await (ServerAgency TokBusy) I.>>= \case
              MsgPong -> pingPongClientPeer

pingPongServerPeer :: Has (Lift IO ) sig m 
                   => Peer PingPong AsServer m (At () StDone) StIdle
pingPongServerPeer = Indexed.do 
    await (ClientAgency TokIdle) I.>>= \case
      MsgDone -> I.do 
        effect $ sendIO (print "recv MsgDone, finish")
        done TokDone ()
      MsgPing -> I.do 
        effect $ sendIO (print "recv MsgPing, send MsgPong")
        yield (ServerAgency TokBusy) MsgPong
        pingPongServerPeer

Describe the solution you'd like

Describe alternatives you've considered

Additional context

ghc currently has a bug in the QualifiedDo syntax, sometimes makes the code look weird.
https://gitlab.haskell.org/ghc/ghc/-/issues/22788

the code I expect:

pingPongClientPeer' :: Has (State Int) sig m 
                   => Peer PingPong AsClient m (At () StDone) StIdle
pingPongClientPeer' = I.do
  At i <- effect (get @Int) 
  if i > 10 
   then I.do
     yield (ClientAgency TokIdle) MsgDone
     done TokDone ()
   else I.do
     yield (ClientAgency TokIdle) MsgPing 
     effect $ modify @Int (+1)
     await (ServerAgency TokBusy) I.>>= \case
       MsgPong -> pingPongClientPeer

Are you willing to implement it?

  • Are you? yes

@coot

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions