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

Add ApplicativeError example to Validated docs #847

Merged
merged 8 commits into from
May 21, 2018

Conversation

raulraja
Copy link
Member

This example shows how you can abstract away failure strategies

@raulraja raulraja requested a review from a team May 17, 2018 22:02
data class FormField(val label: String, val value: String)
data class Email(val value: String)

abstract class Rules<F>(val A: ApplicativeError<F, Nel<ValidationError>>) : ApplicativeError<F, Nel<ValidationError>> by A {
Copy link
Member

@pakoito pakoito May 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A doesn't have to be a field. Why the abstract class and not interface?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is nothing to implement, therefore no need for an interface and if it were an interface then it results in more boilerplate in the interpreters.

interface Rules<F> : ApplicativeError<F, Nel<ValidationError>> {

  val A: ApplicativeError<F, Nel<ValidationError>>

  private fun FormField.contains(needle: String): Kind<F, FormField> =
    if (value.contains(needle, false)) just(this)
    else raiseError(DoesNotContain(needle).nel())

  private fun FormField.maxLength(maxLength: Int): Kind<F, FormField> =
    if (value.length <= maxLength) just(this)
    else raiseError(MaxLength(maxLength).nel())

  fun FormField.validateEmail(): Kind<F, Email> =
    map(contains("@"), maxLength(250), {
      Email(value)
    }).handleErrorWith { raiseError(NotAnEmail(it).nel()) }

}

val errorAccumulatingApplicative : ApplicativeError<ValidatedPartialOf<Nel<ValidationError>>, Nel<ValidationError>> =
  Validated.applicativeError(NonEmptyList.semigroup())

object ErrorAccumulationStrategy : 
  Rules<ValidatedPartialOf<Nel<ValidationError>>>, 
  ApplicativeError<ValidatedPartialOf<Nel<ValidationError>>, Nel<ValidationError>> by errorAccumulatingApplicative {
    override val A: ApplicativeError<ValidatedPartialOf<Nel<ValidationError>>, Nel<ValidationError>>
      get() = Validated.applicativeError(NonEmptyList.semigroup())
}

Normally in tagless the practice I see is that if you can implement the algebra entirely with a type class and not leave any methods abstract to the interpreters then you don't need to use an interface or trait since the very definition of the algebra is abstract by relying on the type classes.

@@ -214,6 +214,79 @@ val houseNumber = config.parse(Read.intRead, "house_number").withEither { either
houseNumber
```

## Abstracting aways validation strategies with `ApplicativeError`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternative validation strategies to Validated: using ApplicativeError? It's a bit more specific than abstracting away. It'd be worthwhile to have a version of this example on the ApplicativeError docs!

Copy link
Member

@pakoito pakoito left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just a couple of comments.

}
```

`Rules` defines abstract behaviors that can be composed and have access to the scoipe of `ApplicativeError` where we can invoke `just` to lift values in to the positive result and `raiseError` into the error context.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: scoipe

Copy link
Member

@nomisRev nomisRev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how easy this snippet is to follow for someone starting out with Arrow. Any1 we can ask?

Validated is a good candidate for new people from coming to OOP so they should be able to follow this snippet easily.

Copy link
Member

@nomisRev nomisRev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how easy this snippet is to follow for someone starting out with Arrow. Any1 we can ask?

Validated is a good candidate for new people from coming to OOP so they should be able to follow this snippet easily.

@raulraja
Copy link
Member Author

raulraja commented May 20, 2018

@nomisRev This example is considered advanced in the context that it requires a bit of knowledge on how Applicative and Applicative Error works though it contains a brief paragraph explaining how they are used in this context:

Rules defines abstract behaviors that can be composed and have access to the scope of ApplicativeError where we can invoke just to lift values in to the positive result and raiseError into the error context.

Are you implying we should not add it to the docs in Validated?

@nomisRev
Copy link
Member

No, I was not implying that at all. Just wondering if we could add something to mark it as advanced and/or point to Applicative/ApplicativeError.

Marking snippets or part of documentation as advanced might make them less intimidating/demotivating for new people.

@raulraja
Copy link
Member Author

raulraja commented May 20, 2018

@nomisRev Added an issue to discuss with @israelperezglez @calvellido . Feel free to contribute any ideas or thoughts there and we can address this in general for all docs since this same jump from beginner to advance happens in many other places.

#850

Copy link
Member

@JorgeCastilloPrz JorgeCastilloPrz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also include some links to this on the Error Handling pattern section?

@codecov
Copy link

codecov bot commented May 20, 2018

Codecov Report

Merging #847 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff            @@
##             master     #847   +/-   ##
=========================================
  Coverage     44.41%   44.41%           
  Complexity      633      633           
=========================================
  Files           294      294           
  Lines          7459     7459           
  Branches        834      834           
=========================================
  Hits           3313     3313           
  Misses         3844     3844           
  Partials        302      302

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e30553f...b9ca113. Read the comment docs.

@JorgeCastilloPrz
Copy link
Member

Thanks :-)

@raulraja raulraja merged commit 089cbed into master May 21, 2018
@raulraja raulraja deleted the rr-validated-applicative-error-docs branch May 21, 2018 12:01
RawToast pushed a commit to RawToast/kategory that referenced this pull request Jul 18, 2018
* Update README.md

* code review

* code review

* Update README.md

* code review

* Update README.md

* fix code snippets missing `)`

* Examples in ApplicativeError and ErrorHandling docs. Ank chockes, maybe memory related.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants