schell / steeloverseer

A file watcher and development tool.
BSD 3-Clause "New" or "Revised" License
128 stars 15 forks source link

Design typed (client-server) interface to steeloverseer #15

Open mitchellwrosen opened 7 years ago

mitchellwrosen commented 7 years ago

I'm thinking of expressing the steeloverseer "server" as a stream of typed "messages", where each one is responded to by the client (front-end: terminal, ncurses, etc).

Haven't though about it too hard but here's what I've come up with:

Use a typed GADT for the message type, produced by the server process and tagged with the expected type of the client response.

data MessageF a where
  -- "I just started a job"
  JobStarted :: JobDescription -> MessageF () -- client responds with (), aka "ok"
  -- "The current job produced a line of output"
  Stdout :: Text -> MessageF ()
  -- "A job exited unsuccessfully, continue?"
  JobDied :: JobDescription -> MessageF Bool

The exact messages obviously need to be fleshed out a bit. Anyways, with this GADT, I think we can reuse the streaming machinery with a clever functor:

data Message a = forall x. Message (MessageF x) (x -> a)

Thus, the overall type of the server is something like

Stream Message IO ()

which expands to (basically)

  Pure ()
| Effect (IO (Stream Message IO ()))
| Step (forall x. (MessageF x) (x -> Stream (Message IO ())))
schell commented 7 years ago

👍 I think that's a great idea. I've been wanting an ncurses interface for a while, but it doesn't make sense to only have that, so this is great.

mitchellwrosen commented 7 years ago

Cool, I'm gonna poke at this tonight. One potential wart is that it strictly encodes a 1:1 request-response style protocol, so any fancy ncurses frontend that wants to have a fully duplex communication channel would be much better off with a socket pair, or just a pair of Chan, or whatever.

Still, playing around in the type system is too much fun :D