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 monadic? #1

Open
davegurnell opened this issue Mar 22, 2017 · 13 comments
Open

Make monadic? #1

davegurnell opened this issue Mar 22, 2017 · 13 comments

Comments

@davegurnell
Copy link
Owner

It's common for some validation rules to be performed against a database (e.g. duplicate checking). Checklist could handle this in one of two ways: either require the user to load related data before running the tests (dodging the issue) or weaving a monad like DBIO in amongst the validation rules.

It may be worth checking rewriting Rule[A, B] as Rule[F[_]: Monad, A, B] to see if this produces something usable.

@Jacoby6000
Copy link
Collaborator

Jacoby6000 commented May 16, 2017

Has any work toward this been done? I can look in to exploring this, but I wouldn't want to duplicate work if you've already made some headway.

I wonder if it would be better to leave Rule as is, and then also have a RuleT as a monad transformer.

I wonder how this will affect composition of rules in general, though.

The good of RuleT

  • If RuleT was created, then Rule[A, B] could just be defined as type Rule[A, B] = RuleT[Id, A, B]
  • Rule[A, B] could be lifted in to any Monad[F]. This would mean that all Rules would be composable with any RuleT, or other Rule.

Considerations of RuleT

  • RuleT[F[_], A, B] could not compose with RuleT[G[_], A, C] unless provided a F ~> G, or G ~> F.

I think Monad transormers work here.

I'm mostly thinking aloud. trying to get discussion going :)

@davegurnell
Copy link
Owner Author

davegurnell commented May 16, 2017 via email

@Jacoby6000
Copy link
Collaborator

Heh, I did some heavy editing after you got that email, I put in some details about what I'm considering above :)

@davegurnell
Copy link
Owner Author

davegurnell commented May 21, 2017

Your approach sounds reasonable to me. I wonder if we're stumbling towards a common functional abstraction. Kleisli seems pretty similar, for example. I guess the difference is in the combinator API we're defining in Checklist.

@Jacoby6000
Copy link
Collaborator

Jacoby6000 commented May 21, 2017

I had considered Kleisli; the main problem that comes with that, is A => F[B] may not be sufficient. I can imagine situations where you might need A => F[A] and then F[A] => F[B].... but now as I'm typing this, I realize that's just Kleisli[F[_], A, A].map[B].

I think rule as a whole might just be

type RuleF[F[_], A, B] = Kleisli[F, A, ValidationMessage Ior B]
type Rule[A, B] = RuleF[Id, A, B]

But with combinators. I'll try to work with this idea and see where it goes.

Tl;dr I think you're right.

@Jacoby6000
Copy link
Collaborator

Jacoby6000 commented Jun 4, 2017

Switching to a Kleisli based encoding has caused lots of problems. None of the functions like map, flatMap, pure, andThen, or any methods that overlap with kleisli (besides contramap) really behave the way users would expect them to. I think it makes sense to go the RuleT route, where you have a standard Rule encoding, and then a MonadTransformer encoding. It is possible to encode all Rules as RuleT, but this can get clunky for people who don't need the extra abstraction.

The work I did can be found here if you're interested (it doesn't quite compile yet) https://github.com/Jacoby6000/checklist/tree/failed/kleisli-encoding

@davegurnell
Copy link
Owner Author

davegurnell commented Jun 5, 2017 via email

@Jacoby6000
Copy link
Collaborator

I'll let you know if I get started on it.

Something I forgot to mention, The Kleisli Encoding works fine for Rule, and behaves exactly how you would expect it to. RuleT is the only thing causing issues with that.

@davegurnell
Copy link
Owner Author

Almost a year later, I spent a little time on an alternative encoding of Rule based directly on Kleisli. The code is in the feature/kleisli branch.

Users can presumably now leverage methods like Kleisli.mapK to wrap whatever base error handling monad they're using (Ior, for example) in a monad transformer.

@rpiaggio
Copy link

rpiaggio commented Jul 24, 2018

Hi there!

I have been experimenting with a monadic version of the checklist precursor library ("io-validation") using an approach similar to @Jacoby6000 's #1 (comment).

(That's the library we actually use, we never got around to migrating to checklist).

It seems to be working so far, so I will attempt to port the changes over to checklist in the next few days and submit a PR.

@rpiaggio
Copy link

This is how code looks like in io-validation:

https://github.com/zoepepper/validation/blob/master/shared/src/test/scala/io/underscore/validation/MonadicValidatorSpec.scala

Whenever and, andPrefix, field or fieldSeq is called, natural transformations are applied if an implicit one is in scope.

@rpiaggio
Copy link

@davegurnell I'd like to try to port the approach we took in https://github.com/zoepepper/validation to checklist. We ended up requiring the context to be Applicative instead of Monad. This is because, composed validations are independent of each other and by taking the Applicative approach we can run them in parallel (assuming the context does the right thing).

I took a look at the feature/kleisli branch and I think that both approaches can be combined, but I'm not that sure.

Do you think it makes more sense to fork from that branch or start with the develp one? In other words, how confident would you say that the Kleisli approach will make it soon into master?

Also, would you be interested in opening up a Gitter channel for the project so that we can discuss more fluidly?

@davegurnell
Copy link
Owner Author

davegurnell commented Aug 12, 2018 via email

rpiaggio added a commit to zoepepper/checklist that referenced this issue Aug 16, 2018
rpiaggio added a commit to zoepepper/checklist that referenced this issue Aug 16, 2018
rpiaggio added a commit to zoepepper/checklist that referenced this issue Aug 16, 2018
rpiaggio added a commit to zoepepper/checklist that referenced this issue Aug 16, 2018
rpiaggio added a commit to zoepepper/checklist that referenced this issue Aug 16, 2018
rpiaggio added a commit to zoepepper/checklist that referenced this issue Aug 16, 2018
rpiaggio added a commit to zoepepper/checklist that referenced this issue Aug 17, 2018
rpiaggio added a commit to zoepepper/checklist that referenced this issue Aug 17, 2018
rpiaggio added a commit to zoepepper/checklist that referenced this issue Aug 17, 2018
rpiaggio added a commit to zoepepper/checklist that referenced this issue Aug 19, 2018
rpiaggio added a commit to zoepepper/checklist that referenced this issue Aug 19, 2018
rpiaggio added a commit to zoepepper/checklist that referenced this issue Aug 20, 2018
rpiaggio added a commit to zoepepper/checklist that referenced this issue Aug 20, 2018
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

3 participants