Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make ProcessM a transformer (or add MonadProcessM) #5

Open
DylanLukes opened this issue Sep 25, 2011 · 4 comments
Open

Make ProcessM a transformer (or add MonadProcessM) #5

DylanLukes opened this issue Sep 25, 2011 · 4 comments

Comments

@DylanLukes
Copy link

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
Copy link
Owner

jepst commented Sep 26, 2011

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
Copy link
Author

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
Copy link
Owner

jepst commented Sep 26, 2011

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
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants