jepst / CloudHaskell

A distributed computing framework for Haskell
http://hackage.haskell.org/package/remote
BSD 3-Clause "New" or "Revised" License
347 stars 22 forks source link

Make ProcessM a transformer (or add MonadProcessM) #5

Open DylanLukes opened 13 years ago

DylanLukes commented 13 years ago

In some examples I've been writing, I've been trying to use StateT MyState ProcessM (). Generally the issue with this is that all of the ProcessM stuff has to be lifted. So there are two solutions.

Make ProcessM a transformer so I can use MonadState.

Add a MonadProcessM class I can instance my monad stack with so I can lift the stuff up automatically.

Or, you know, both.

jepst commented 13 years ago

You're right that more flexibility in deploying ProcessM would be nice, but it's a pretty big change either way.

ProcessM could be a transformer, but you'd still have to lift your stateful actions. This makes it easier to rearrange the monad stack, but it would also break existing code, not only in changing the signatures of the existing API, but would also make a mess of Remote.Call, which should generate RPC stubs.

With a hypothetical ProcessT transformer, we could write code that looks like this:

something :: ProcessT (StateT MyState IO) Int
something = 
       do lift $ lift $ putStrLn "Hi"   -- IO action
          lift $ put MyState {noodle=9}  -- State action
          say "Yo" -- Process action
          return 3

I'm not convinced this is a huge improvement over lifting all the Process actions. But, I am open to persuasion and I would probably accept a patch.

DylanLukes commented 13 years ago

I think ProcessT implies IO actually, so that might not work exactly like that (How would a Process work in a non-IO context?). And also, a single liftIO could be used to bring it all the way up if ProcessT StateT is a MonadIO instance.

Well, I think the crux is that StateT has only four actions which can be automatically lifted by a MonadProcess class, whereas ProcessM has many. So, with StateT MyState ProcessM (), all ProcessM actions must be lifted. With ProcessT (StateT MyState Identity) (), a type class can be used to lift get/put/gets/modify.

This is generally a bit nicer, so I'm doing this myself in my CloudHaskell-OTP project. I'm trying to generally put a "nicer" layer of abstraction on top. i.e, almost every OTP process passes State to itself, encompassing the action in the state monad makes for some prettier code, especially in combination with Data.Lens.

I may submit a patch, maybe not...

jepst commented 13 years ago

I took a look at your OTP project and it looks awesome. I'd love to help.

In regard to ChildSpec, though, I think you'll need to use Closure; Haskell is lazy but ProcessM but process spawning isn't.

DylanLukes commented 13 years ago

Ah thanks! That's a very good point :).

I'm very busy with other work, but I'm trying to work a little on this here and there. It's mostly for personal projects... but I'll try to keep it generalized.