data-easy 0.4 → 0.7.0
raw patch · 2 files changed
Files
- data-easy.cabal +14/−10
- src/Data/Easy.hs +268/−48
data-easy.cabal view
@@ -1,12 +1,18 @@ name: data-easy-version: 0.4-synopsis: Consistent set of utility functions for Maybe, Either, List, Monoids.+version: 0.7.0+synopsis: Consistent set of utility functions for Maybe, Either, List and Monoids. description: Easy to use set of utility functions, implementing a Data.Maybe like interface for other common types, like Either, List, Bool, Tuple, or even member of the Monoid type class. Also features a set of conversion functions among them, using sensible defaults.-homepage: https://github.com/jcristovao/easy-data+ .+ Most of these functions are one liners, and this library started out as a+ self-educational project, which nevertheless proved to to be useful on its+ own right.+ .+ Please feel free to contribute and/or suggest changes.+homepage: https://github.com/jcristovao/data-easy license: BSD3 license-file: LICENSE author: João Cristóvão@@ -18,7 +24,7 @@ -- extra-source-files: -- Constraint on the version of Cabal needed to build this package.-cabal-version: >=1.18+cabal-version: >=1.10 library@@ -29,8 +35,7 @@ -- other-modules: -- Other library packages from which modules are imported.- build-depends : base >= 4.6 && < 4.8- , either >= 4.1.1+ build-depends : base >= 4.6 && < 4.11 , safe >= 0.3.3 , containers >= 0.5.0.0 @@ -46,13 +51,12 @@ type: exitcode-stdio-1.0 main-is: main.hs hs-source-dirs: test, src- build-depends: base >= 4.6 && < 4.8- , transformers >= 0.3- , either >= 4.1.1+ build-depends: base >= 4.6 && < 4.9+ , transformers >= 0.4 && < 0.5 , safe >= 0.3.3 , containers >= 0.5.0.0 , text >= 0.11.3- , errors >= 1.4.3+ , errors >= 2.0 , directory >= 1.2.0.1 , QuickCheck >= 2.7 && < 2.8 , HUnit >= 1.2.5.2
src/Data/Easy.hs view
@@ -4,13 +4,6 @@ -- @'Bool'@ counterparts to the functions originally defined in -- "Data.Maybe", whenever applicable. ----- Most functions of "Data.Maybe" are re-exported, so you may import just this--- module instead. The only exception(s) are partial functions such as--- fromJust. Here, the safer alternatives from the "Safe" package are--- prefered (and imported) instead. All functions that take a default value--- as a replacement for an invalid value usually accept it as their first--- parameter, inline with the convention followed by the "Safe" package.--- -- This module also adds some extra useful functions, that can be found -- in otherwise disperse packages, pages, mailing lists, etc. -- A relevant link will be included whenever appropriate, or just a simple@@ -41,8 +34,8 @@ -- -- @utility-ht@ : <http://hackage.haskell.org/package/utility-ht> ----- Note that "Safe" and @either@ (the "Data.Either.Combinators" module) are--- re-exported by this module. Please notify me if you think I'm missing+-- Note that the "Safe" module is re-exported by this module.+-- Please notify me if you think I'm missing -- some other library. -- -- For monad related functions, check my other related module,@@ -55,13 +48,7 @@ -- module Data.Easy ( -- * Module exports- module Data.Maybe- , module Data.Either- , module Data.Either.Combinators- , module Data.Tuple- , module Data.Ord- , module Data.Function- , module Safe+ module Safe -- * Additional functions @@ -73,8 +60,23 @@ , monoidToMaybe -- ** Either- -- | Many of the functions are already defined in either "Data.Either" or- -- "Data.Either.Combinators" from the "either" package.+ -- | Copied most of the functions from "Data.Either.Combinators",+ -- from the "either" package. This package has a huge import list,+ -- unnecessary for such simple combinators.+ , fromLeft+ , fromRight+ , fromLeft'+ , fromRight'+ , mapBoth+ , mapLeft+ , mapRight+ , whenLeft+ , whenRight+ , unlessLeft+ , unlessRight+ , leftToMaybe+ , rightToMaybe+ , fromRightNote , fromLeftNote , fromEither@@ -255,23 +257,17 @@ , (?&&) , (?&&\) , allCond- , allCond' , anyCond- , anyCond' ) where import Data.Maybe import Data.Either-#if __GLASGOW_HASKELL__ >= 707-import Data.Either.Combinators hiding (isLeft,isRight)-#else-import Data.Either.Combinators-#endif-import Data.Tuple-import Data.Ord-import Data.Function-import Data.Monoid+-- #if __GLASGOW_HASKELL__ >= 707+-- import Data.Either.Combinators hiding (isLeft,isRight)+-- #else+-- import Data.Either.Combinators+-- #endif import Safe import qualified Data.List as L import qualified Data.Set as Set@@ -296,6 +292,243 @@ -- Either -------------------------------------------------------------------- ------------------------------------------------------------------------------ +-- From Data.Either.Combinators ----------------------------------------------++-- ---------------------------------------------------------------------------+-- Functions over Either++-- | Extracts the element out of a 'Left' and+-- throws an error if its argument take the form @'Right' _@.+--+-- Using @Control.Lens@:+--+-- @+-- 'fromLeft'' x ≡ x^?!_Left+-- @+--+-- >>> fromLeft' (Left 12)+-- 12+fromLeft' :: Either a b -> a+fromLeft' (Right _) = error "Data.Easy.fromLeft: Argument takes form 'Right _'" -- yuck+fromLeft' (Left x) = x++-- | Extracts the element out of a 'Right' and+-- throws an error if its argument take the form @'Left' _@.+--+-- Using @Control.Lens@:+--+-- @+-- 'fromRight'' x ≡ x^?!_Right+-- @+--+-- >>> fromRight' (Right 12)+-- 12+fromRight' :: Either a b -> b+fromRight' (Left _) = error "Data.Easy.fromRight: Argument takes form 'Left _'" -- yuck+fromRight' (Right x) = x++-- | The 'mapBoth' function takes two functions and applies the first if iff the value+-- takes the form @'Left' _@ and the second if the value takes the form @'Right' _@.+--+-- Using @Data.Bifunctor@:+--+-- @+-- 'mapBoth' = bimap+-- @+--+-- Using @Control.Arrow@:+--+-- @+-- 'mapBoth' = ('Control.Arrow.+++')+-- @+--+-- >>> mapBoth (*2) (*3) (Left 4)+-- Left 8+--+-- >>> mapBoth (*2) (*3) (Right 4)+-- Right 12+mapBoth :: (a -> c) -> (b -> d) -> Either a b -> Either c d+mapBoth f _ (Left x) = Left (f x)+mapBoth _ f (Right x) = Right (f x)++-- | The 'mapLeft' function takes a function and applies it to an Either value+-- iff the value takes the form @'Left' _@.+--+-- Using @Data.Bifunctor@:+--+-- @+-- 'mapLeft' = first+-- @+--+-- Using @Control.Arrow@:+--+-- @+-- 'mapLeft' = ('Control.Arrow.left')+-- @+--+-- Using @Control.Lens@:+--+-- @+-- 'mapLeft' = over _Left+-- @+--+-- >>> mapLeft (*2) (Left 4)+-- Left 8+--+-- >>> mapLeft (*2) (Right "hello")+-- Right "hello"+mapLeft :: (a -> c) -> Either a b -> Either c b+mapLeft f = mapBoth f id++-- | The 'mapRight' function takes a function and applies it to an Either value+-- iff the value takes the form @'Right' _@.+--+-- Using @Data.Bifunctor@:+--+-- @+-- 'mapRight' = second+-- @+--+-- Using @Control.Arrow@:+--+-- @+-- 'mapRight' = ('Control.Arrow.right')+-- @+--+-- Using @Control.Lens@:+--+-- @+-- 'mapRight' = over _Right+-- @+--+-- >>> mapRight (*2) (Left "hello")+-- Left "hello"+--+-- >>> mapRight (*2) (Right 4)+-- Right 8+mapRight :: (b -> c) -> Either a b -> Either a c+mapRight = mapBoth id++-- | The 'whenLeft' function takes an 'Either' value and a function which returns a monad.+-- The monad is only executed when the given argument takes the form @'Left' _@, otherwise+-- it does nothing.+--+-- Using @Control.Lens@:+--+-- @+-- 'whenLeft' ≡ forOf_ _Left+-- @+--+-- >>> whenLeft (Left 12) print+-- 12+whenLeft :: Applicative m => Either a b -> (a -> m ()) -> m ()+whenLeft (Left x) f = f x+whenLeft _ _ = pure ()++-- | The 'whenRight' function takes an 'Either' value and a function which returns a monad.+-- The monad is only executed when the given argument takes the form @'Right' _@, otherwise+-- it does nothing.+--+-- Using @Data.Foldable@:+--+-- @+-- 'whenRight' ≡ 'forM_'+-- @+--+-- Using @Control.Lens@:+--+-- @+-- 'whenRight' ≡ forOf_ _Right+-- @+--+-- >>> whenRight (Right 12) print+-- 12+whenRight :: Applicative m => Either a b -> (b -> m ()) -> m ()+whenRight (Right x) f = f x+whenRight _ _ = pure ()++-- | A synonym of 'whenRight'.+unlessLeft :: Applicative m => Either a b -> (b -> m ()) -> m ()+unlessLeft = whenRight++-- | A synonym of 'whenLeft'.+unlessRight :: Applicative m => Either a b -> (a -> m ()) -> m ()+unlessRight = whenLeft++-- | Extract the left value or a default.+--+-- @+-- 'fromLeft' ≡ 'either' 'id'+-- @+--+-- >>> fromLeft "hello" (Right 42)+-- "hello"+--+-- >>> fromLeft "hello" (Left "world")+-- "world"+fromLeft :: a -> Either a b -> a+fromLeft _ (Left x) = x+fromLeft x _ = x++-- | Extract the right value or a default.+--+-- @+-- 'fromRight' b ≡ 'either' b 'id'+-- @+--+-- >>> fromRight "hello" (Right "world")+-- "world"+--+-- >>> fromRight "hello" (Left 42)+-- "hello"+fromRight :: b -> Either a b -> b+fromRight _ (Right x) = x+fromRight x _ = x++-- | Maybe get the 'Left' side of an 'Either'.+--+-- @+-- 'leftToMaybe' ≡ 'either' 'Just' ('const' 'Nothing')+-- @+--+-- Using @Control.Lens@:+--+-- @+-- 'leftToMaybe' ≡ preview _Left+-- 'leftToMaybe' x ≡ x^?_Left+-- @+--+-- >>> leftToMaybe (Left 12)+-- Just 12+--+-- >>> leftToMaybe (Right 12)+-- Nothing+leftToMaybe :: Either a b -> Maybe a+leftToMaybe = either Just (const Nothing)++-- | Maybe get the 'Right' side of an 'Either'.+--+-- @+-- 'rightToMaybe' ≡ 'either' ('const' 'Nothing') 'Just'+-- @+--+-- Using @Control.Lens@:+--+-- @+-- 'rightToMaybe' ≡ preview _Right+-- 'rightToMaybe' x ≡ x^?_Right+-- @+--+-- >>> rightToMaybe (Left 12)+-- Nothing+--+-- >>> rightToMaybe (Right 12)+-- Just 12+rightToMaybe :: Either a b -> Maybe b+rightToMaybe = either (const Nothing) Just++-- New functions / Renamed functions -----------------------------------------+ -- | Force a right value, or otherwise fail with provided error message -- -- > fromRightNote err = either (error err) id@@ -310,7 +543,8 @@ -- | Force a right value, providing a default value if the Either is Left fromEither :: b -> Either a b -> b-fromEither = fromRight+fromEither _ (Right x) = x+fromEither x _ = x -- | Extract the first element of a list as a Right value, or else use the -- default value provided as a Left value@@ -361,7 +595,7 @@ -- @ -- eitherToMaybe :: Either a b -> Maybe b-eitherToMaybe = rightToMaybe+eitherToMaybe = either (const Nothing) Just -- | eitherToMonoid extract the right sided monoid into a single monoid@@ -462,12 +696,12 @@ -- -- > nubSort = Set.toAscList . Set.fromList ---nubSort :: (Eq a, Ord a) => [a] -> [a]+nubSort :: (Ord a) => [a] -> [a] nubSort = Set.toAscList . Set.fromList -- | Sort, nub (remove duplicates) and remove initial empty value, if it -- exists. See 'nubSort'.-nubSort' :: (Eq a, Ord a, Monoid a) => [a] -> [a]+nubSort' :: (Ord a, Monoid a) => [a] -> [a] nubSort' lst = case nubSort lst of [] -> [] (x:xs) -> if isEmpty x then xs else x:xs@@ -911,7 +1145,7 @@ -- to promote values into a monoid -- -- > listToMonoid = headDef mempty-listToMonoid :: (Eq a, Monoid a) => [a] -> a+listToMonoid :: (Monoid a) => [a] -> a listToMonoid = headDef mempty -- | monoidToList convert an empty monoid into an empty list,@@ -1157,12 +1391,6 @@ allCond _ [] = False allCond value lst = and . mapV value $ lst --- | Flipped allCond------ > flip allCond-allCond' :: [a -> Bool] -> a -> Bool-allCond' = flip allCond- -- | Apply a list of boolean checks/tests to a variable, and return (True) -- if /any/ of them passed. --@@ -1173,11 +1401,3 @@ anyCond :: a -> [a -> Bool] -> Bool anyCond _ [] = False anyCond value lst = or . mapV value $ lst---- | Flipped anyCond------ > flip anyCond-anyCond' :: [a -> Bool] -> a -> Bool-anyCond' = flip anyCond--