-
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* [#24] Extra interface functions Resolves #24 * Rename vars * Add hs-boot for Validation to break cyclic deps
- Loading branch information
Showing
6 changed files
with
258 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module Validation | ||
( Validation (..) | ||
, validation | ||
) where | ||
|
||
|
||
data Validation e a | ||
= Failure e | ||
| Success a | ||
|
||
instance (Semigroup e) => Applicative (Validation e) | ||
|
||
validation :: (e -> x) -> (a -> x) -> Validation e a -> x |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
{- | | ||
Copyright: (c) 2020 Kowainik | ||
SPDX-License-Identifier: MPL-2.0 | ||
Maintainer: Kowainik <[email protected]> | ||
Helpful combinators to work with 'Validation' data type. | ||
-} | ||
|
||
module Validation.Combinators | ||
( validateAll | ||
|
||
-- * When* functions | ||
, whenSuccess | ||
, whenFailure | ||
, whenSuccess_ | ||
, whenFailure_ | ||
, whenSuccessM | ||
, whenFailureM | ||
, whenSuccessM_ | ||
, whenFailureM_ | ||
|
||
-- * 'Maybe' conversion | ||
, failureToMaybe | ||
, successToMaybe | ||
, maybeToFailure | ||
, maybeToSuccess | ||
|
||
) where | ||
|
||
import Data.Foldable (foldl') | ||
|
||
import {-# SOURCE #-} Validation (Validation (..), validation) | ||
|
||
|
||
{- | Validate all given checks in a 'Foldable'. Returns the 'Success' of the | ||
start element when all checks are successful. | ||
A basic example of usage could look like this: | ||
@ | ||
> let validatePassword = validateAll | ||
[ validateEmptyPassword | ||
, validateShortPassword | ||
] | ||
> validateAll "VeryStrongPassword" | ||
Success "VeryStrongPassword" | ||
> validateAll "" | ||
Failure (EmptyPassword :| [ShortPassword]) | ||
@ | ||
-} | ||
validateAll | ||
:: forall e b a f | ||
. (Foldable f, Semigroup e) | ||
=> f (a -> Validation e b) | ||
-> a | ||
-> Validation e a | ||
validateAll fs a = foldl' (\res f -> res <* f a) (Success a) fs | ||
{-# INLINE validateAll #-} | ||
|
||
{- | Applies the given action to 'Validation' if it is 'Failure' and returns the | ||
result. In case of 'Success' the default value is returned. | ||
>>> whenFailure "bar" (Failure 42) (\a -> "foo" <$ print a) | ||
42 | ||
"foo" | ||
>>> whenFailure "bar" (Success 42) (\a -> "foo" <$ print a) | ||
"bar" | ||
-} | ||
whenFailure :: Applicative f => x -> Validation e a -> (e -> f x) -> f x | ||
whenFailure _ (Failure e) f = f e | ||
whenFailure a (Success _) _ = pure a | ||
{-# INLINE whenFailure #-} | ||
|
||
{- | Applies given action to the 'Validation' content if it is 'Failure'. | ||
Similar to 'whenFailure' but the default value is '()'. | ||
>>> whenFailure_ (Success 42) putStrLn | ||
>>> whenFailure_ (Failure "foo") putStrLn | ||
foo | ||
-} | ||
whenFailure_ :: Applicative f => Validation e a -> (e -> f ()) -> f () | ||
whenFailure_ = whenFailure () | ||
{-# INLINE whenFailure_ #-} | ||
|
||
{- | Monadic version of 'whenFailure'. | ||
Applies monadic action to the given 'Validation' in case of 'Failure'. | ||
Returns the resulting value, or provided default. | ||
>>> whenFailureM "bar" (pure $ Failure 42) (\a -> "foo" <$ print a) | ||
42 | ||
"foo" | ||
>>> whenFailureM "bar" (pure $ Success 42) (\a -> "foo" <$ print a) | ||
"bar" | ||
-} | ||
whenFailureM :: Monad m => x -> m (Validation e a) -> (e -> m x) -> m x | ||
whenFailureM x mv f = mv >>= \v -> whenFailure x v f | ||
{-# INLINE whenFailureM #-} | ||
|
||
{- | Monadic version of 'whenFailure_'. | ||
Applies monadic action to the given 'Validation' in case of 'Failure'. | ||
Similar to 'whenFailureM' but the default is '()'. | ||
>>> whenFailureM_ (pure $ Success 42) putStrLn | ||
>>> whenFailureM_ (pure $ Failure "foo") putStrLn | ||
foo | ||
-} | ||
whenFailureM_ :: Monad m => m (Validation e a) -> (e -> m ()) -> m () | ||
whenFailureM_ mv f = mv >>= \v -> whenFailure_ v f | ||
{-# INLINE whenFailureM_ #-} | ||
|
||
{- | Applies the given action to 'Validation' if it is 'Success' and returns the | ||
result. In case of 'Failure' the default value is returned. | ||
>>> whenSuccess "bar" (Failure "foo") (\a -> "success!" <$ print a) | ||
"bar" | ||
>>> whenSuccess "bar" (Success 42) (\a -> "success!" <$ print a) | ||
42 | ||
"success!" | ||
-} | ||
whenSuccess :: Applicative f => x -> Validation e a -> (a -> f x) -> f x | ||
whenSuccess x (Failure _) _ = pure x | ||
whenSuccess _ (Success a) f = f a | ||
{-# INLINE whenSuccess #-} | ||
|
||
{- | Applies given action to the 'Validation' content if it is 'Success'. | ||
Similar to 'whenSuccess' but the default value is '()'. | ||
>>> whenSuccess_ (Failure "foo") print | ||
>>> whenSuccess_ (Success 42) print | ||
42 | ||
-} | ||
whenSuccess_ :: Applicative f => Validation e a -> (a -> f ()) -> f () | ||
whenSuccess_ = whenSuccess () | ||
{-# INLINE whenSuccess_ #-} | ||
|
||
{- | Monadic version of 'whenSuccess'. | ||
Applies monadic action to the given 'Validation' in case of 'Success'. | ||
Returns the resulting value, or provided default. | ||
>>> whenSuccessM "bar" (pure $ Failure "foo") (\a -> "success!" <$ print a) | ||
"bar" | ||
>>> whenSuccessM "bar" (pure $ Success 42) (\a -> "success!" <$ print a) | ||
42 | ||
"success!" | ||
-} | ||
whenSuccessM :: Monad m => x -> m (Validation e a) -> (a -> m x) -> m x | ||
whenSuccessM x mv f = mv >>= \v -> whenSuccess x v f | ||
{-# INLINE whenSuccessM #-} | ||
|
||
{- | Monadic version of 'whenSuccess_'. | ||
Applies monadic action to the given 'Validation' in case of 'Success'. | ||
Similar to 'whenSuccessM' but the default is '()'. | ||
>>> whenSuccessM_ (pure $ Failure "foo") print | ||
>>> whenSuccessM_ (pure $ Success 42) print | ||
42 | ||
-} | ||
whenSuccessM_ :: Monad m => m (Validation e a) -> (a -> m ()) -> m () | ||
whenSuccessM_ mv f = mv >>= \v -> whenSuccess_ v f | ||
{-# INLINE whenSuccessM_ #-} | ||
|
||
|
||
{- | Maps 'Failure' of 'Validation' to 'Just'. | ||
>>> failureToMaybe (Failure True) | ||
Just True | ||
>>> failureToMaybe (Success "aba") | ||
Nothing | ||
-} | ||
failureToMaybe :: Validation e a -> Maybe e | ||
failureToMaybe = validation Just (const Nothing) | ||
{-# INLINE failureToMaybe #-} | ||
|
||
{- | Maps 'Success' of 'Validation' to 'Just'. | ||
>>> successToMaybe (Failure True) | ||
Nothing | ||
>>> successToMaybe (Success "aba") | ||
Just "aba" | ||
-} | ||
successToMaybe :: Validation e a -> Maybe a | ||
successToMaybe = validation (const Nothing) Just | ||
{-# INLINE successToMaybe #-} | ||
|
||
{- | Maps 'Just' to 'Failure' In case of 'Nothing' it wraps the given default | ||
value into 'Success'. | ||
>>> maybeToFailure True (Just "aba") | ||
Failure "aba" | ||
>>> maybeToFailure True Nothing | ||
Success True | ||
-} | ||
maybeToFailure :: a -> Maybe e -> Validation e a | ||
maybeToFailure a = maybe (Success a) Failure | ||
{-# INLINE maybeToFailure #-} | ||
|
||
{- | Maps 'Just' to 'Success'. In case of 'Nothing' it wraps the given default | ||
value into 'Failure' | ||
>>> maybeToSuccess True (Just "aba") | ||
Success "aba" | ||
>>> maybeToSuccess True Nothing | ||
Failure True | ||
-} | ||
maybeToSuccess :: e -> Maybe a -> Validation e a | ||
maybeToSuccess e = maybe (Failure e) Success | ||
{-# INLINE maybeToSuccess #-} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters