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

Reader Monad for Flags #4492

Open
angerman opened this issue May 4, 2017 · 8 comments
Open

Reader Monad for Flags #4492

angerman opened this issue May 4, 2017 · 8 comments
Labels
re: monad On refactoring cabal-install to use custom monads type: refactor

Comments

@angerman
Copy link
Collaborator

angerman commented May 4, 2017

cabal is designed mostly without the use of monads. This leads to functions passing context via arguments along. And even so explicitly.

It seems like there is some interest in having cabal be partially refactored to use a Reader Monad for Flags (global, command specific, and verbosity).

I believe carrying a Record along as context instead of passing arguments explicitly might improve the situation, however a Monadic approach would even free one of having to pass the context explicitly.

The questions that remains are:

  • 👍 or 👎
  • How should the monad stack look? (I'd prefer not to hand roll it)
  • What monad libraries can we use for convenience? (boot library restrictions)
@angerman
Copy link
Collaborator Author

angerman commented May 4, 2017

@hvr pointed out the following #1940 for previous discussion of the Shell Monad

@ezyang
Copy link
Contributor

ezyang commented May 4, 2017

A few notes:

  • Introducing a new monad to Cabal library is a massive BC break for basically all Custom client scripts. This might be OK, but you should make the decision knowing you are breaking people, and plan accordingly.

  • In my experience, all you need is IO plus Reader. But I think that the most important thing is to make the monad abstract.

  • If it's just IO and Reader, rolling it by hand is really simple, not much code at all. But when we get the Parsec parser we will have a new dep on transformers so you could also use that library.

@phadej
Copy link
Collaborator

phadej commented May 4, 2017

I'm as well a bit worried about BC break, yet in longer run it will surely be good (if we need to add new contextual value).

@hvr
Copy link
Member

hvr commented May 4, 2017

See also #4040 (comment) (which is what lead me to learn about #1940) which is why I'd like to get a Monad in place rather than having to pass around yet another argument (or come up with some other hack).

@angerman
Copy link
Collaborator Author

angerman commented May 5, 2017

Finally, would this not insulate us precisely from BC changes in the future? If the underlying Monad evolved (and gains additional functionality), downstream consumers of it would see no breaking changes, but just a more advanced monad, while the existing functionality would stay the same?

I'd agree with @ezyang on a newtype monad, without exposing the stack much. @ndmitchell wrote

The cool thing about Haskell is that I've been able to completely replace the underlying Shake Action monad from StateT/IO, to ReaderT/IO, to ReaderT/ContT/IO, without ever breaking any users of Shake. Haskell allows me to produce effective and flexible abstractions.

Which is precisely what we want I believe.

@BardurArantsson
Copy link
Collaborator

Also relevant: https://www.fpcomplete.com/blog/2017/07/the-rio-monad for a bit of practical experience with a project which is (probably) very similar to cabal-install :).

@fgaz
Copy link
Member

fgaz commented Sep 1, 2021

@andreasabel I think this is the main "monad" ticket, but there are comments about it in other tickets too, eg. #4357 (comment) #6977 (comment)

@andreasabel andreasabel added the re: monad On refactoring cabal-install to use custom monads label Sep 2, 2021
@andreasabel
Copy link
Member

My preferred way is to define "service classes" like

class Monad m => MonadOptions m where
  askOptions :: m Options

and then functions that need to have access to the options (but are other ways pure) can have types like

foo :: MonadOptions m -> Foo -> m Bar

Rather than with a monolithic "monad for everything", like the Cabal monad, one can have more control over effects with dedicated service classes. In the end, it could be that the Cabal monad is the only one to instantiate these services

instance MonadOptions Cabal where
  askOptions = ...

but the reader of the code still gets information about which effects they have to worry.

Here is one example from the Agda codebase: https://github.com/agda/agda/blob/6e4fb9d0be1f8236170eac1d7d2514fa10d4c626/src/full/Agda/Interaction/Options/HasOptions.hs#L17-L39

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
re: monad On refactoring cabal-install to use custom monads type: refactor
Projects
None yet
Development

No branches or pull requests

7 participants