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
[#100] Add Validation data type to Extra modules #106
Conversation
It seems the tests are failing because module Relude.Foldable.Reexport
( module Data.Foldable
, module Data.Traversable
#if MIN_VERSION_base(4,10,0)
, module Data.Bifoldable
, module Data.Bitraversable
#endif
) where
|
@mauriciofierrom , thanks for your contribution! Regarding the CI issue, I guess, the same |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! I have several comments. And, as @vrom911 pointed out, we should use -XCPP
here to have Bifoldable
and Bitraversable
instances only for higher base
versions
src/Relude/Extra/Validation.hs
Outdated
|
||
{- | | ||
Copyright: (c) 2014 Chris Allen, Edward Kmett | ||
(c) 2018 Kowainic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor typo here, should be Kowainik
🙂
src/Relude/Extra/Validation.hs
Outdated
liftA2 _ (Failure e) (Failure e') = Failure (e <> e') | ||
liftA2 _ (Failure e) (Success _) = Failure e | ||
liftA2 _ (Success _) (Failure e) = Failure e | ||
liftA2 f (Success a) (Success a') = Success (f a a') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just minor comment, but I think that instead of a'
this variable could be named b
to match type more precisely. The same trick cannot be done with e
and e'
because type variable is e
in both cases. But I think that we can have e1
and e2
or el
(e-left) and er
(e-right). It's just my personal dislike of '
in names because according to common Haskell convention '
is usually used at the end of functions to mark it as strict (like foldl
and foldl'
).
src/Relude/Extra/Validation.hs
Outdated
(*>) = liftA2 (flip const) | ||
|
||
(<*) :: Validation e a -> Validation e b -> Validation e a | ||
(<*) = liftA2 const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are the default definitions of <*
and *>
. I wonder, if we can write them more efficiently if we do pattern-matching explicitly? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are both defined based on liftA2
, which is a custom implementation and actually uses pattern-matching explicitly, so I thought perhaps it was best to just leave these methods for readibility's sake. I can change it anyway, WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's keep the default implementation here as well 👍
src/Relude/Extra/Validation.hs
Outdated
fold (Failure _) = mempty | ||
|
||
foldMap :: Monoid m => (a -> m) -> Validation e a -> m | ||
foldMap f = foldr (mappend . f) mempty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think foldMap
can be written more efficiently more via explicit pattern-matching
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kind of the same thing as with <*
but in terms of foldr
. I can change it anyway, WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, for <*
and *>
we're kinda hope for the inlining and optimizations and implementing <*
as liftA2 const
is not a big deal. But for foldMap
optimizations might not trigger because the implementation is more difficult. So it's better to pattern-match here explicitly as well.
src/Relude/Extra/Validation.hs
Outdated
validationToEither :: Validation e a -> Either e a | ||
validationToEither x = case x of | ||
Failure e -> Left e | ||
Success a -> Right a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer using -XLabmdaCase
language extension and write it like:
validationToEither = \case
Failure e -> Left e
Success a -> Right a
src/Relude/Extra/Validation.hs
Outdated
|
||
-- | Transform an 'Either' into a 'Validation'. | ||
eitherToValidation :: Either e a -> Validation e a | ||
eitherToValidation x = case x of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here as for validationToEither
{-# INLINE fmap #-} | ||
{-# INLINE (<$) #-} | ||
|
||
instance Semigroup e => Applicative (Validation e) where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be really great to add couple doctest
tests to this instance to show different cases 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good 👍
src/Relude/Extra/Validation.hs
Outdated
, eitherToValidation | ||
) where | ||
|
||
import Data.Function (const) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think relude
exports const
, no need to have redundant import
@@ -0,0 +1,150 @@ | |||
{-# LANGUAGE InstanceSigs #-} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After reading this module I'm now even more sure that -XInstanceSigs
should be enabled by default!
@@ -89,6 +89,7 @@ every module in your package by modifying your "Prelude" file: | |||
@newtype@. | |||
* __"Relude.Extra.Tuple"__: functions for working with tuples. | |||
* __"Relude.Extra.Type"__: functions for inspecting and working with types. | |||
* __"Relude.Extra.Validation"__: 'Validation' data type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for updating the documentation! ❤️
It seems |
Hmm... Yeah, having the default implementation for |
src/Relude/Extra/Validation.hs
Outdated
-- | Examples: | ||
-- | ||
-- >>> let fa = Success (*3) :: Validation Text (Int -> Int) | ||
-- >>> let ga = Success (*4) :: Validation Text (Int -> Int) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example purposes it's better to use [Text]
instead of just Text
. It's not a good idea to use Text
as a monoidal error, so let's not show non-idiomatic examples in our documentation examples.
src/Relude/Extra/Validation.hs
Outdated
{-# INLINE fmap #-} | ||
{-# INLINE (<$) #-} | ||
|
||
-- | Examples: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it's a good idea to write this as ==== __Examples__
to make them expandable 🤔
Not sure how it will look like.
Also, IMO, for multiline haddock comments it's better to use: the following style
{- |
-}
so you won't need to add --
at the beginning of each line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that non-expandable is better 🙂
instance Traversable (Validation e) where | ||
traverse :: Applicative f => (a -> f b) -> Validation e a -> f (Validation e b) | ||
traverse f (Success a) = Success <$> f a | ||
traverse _ (Failure e) = pure (Failure e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can also implement sequenceA
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing 🔥
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great change!
Resolves #100
Add
Validation
data type toExtra
modules.Checklist:
HLint
hlint.dhall
accordingly to my changes (add new rules for the new imports, remove old ones, when they are outdated, etc.)..hlint.yaml
file (see this instructions).General
stylish-haskell
file.[ci skip]
text to the docs-only related commit's name.