IsNull (empty) → 0.3.0.0
raw patch · 7 files changed
+308/−0 lines, 7 filesdep +HUnitdep +QuickCheckdep +basesetup-changed
Dependencies added: HUnit, QuickCheck, base, base-compat, bytestring, containers, hspec, quickcheck-instances, system-filepath, text, unordered-containers, vector
Files
- IsNull.cabal +58/−0
- LICENSE +30/−0
- README.md +61/−0
- Setup.hs +2/−0
- src/Data/IsNull.hs +53/−0
- src/Data/IsNull/Internal.hs +102/−0
- test/main.hs +2/−0
+ IsNull.cabal view
@@ -0,0 +1,58 @@+name: IsNull+version: 0.3.0.0+synopsis: A typeclass to determine if a given value is null.+description: A typeclass to determine if a given foldable type+ (or other) is empty ~ null ~ invalid.+ The definition is intentionally vague, to cover types+ from Either to Text and Sets.+homepage: https://github.com/jcristovao/IsNull+license: BSD3+license-file: LICENSE+author: João Cristóvão+maintainer: jmacristovao@gmail.com+category: Data+build-type: Simple++extra-source-files: README.md++-- Constraint on the version of Cabal needed to build this package.+cabal-version: >=1.16++library+ other-modules: Data.IsNull.Internal+ exposed-modules: Data.IsNull+ build-depends: base >= 4.5 && < 4.8+ , base-compat >= 0.5 && < 0.6+ , containers >= 0.5 && < 0.6+ , text >= 0.11.3 && < 1.3+ , bytestring >= 0.10.0 && < 1.0++ hs-source-dirs: src+ ghc-options: -Wall+ default-language: Haskell2010+ +-- the test suite checks for most (modern) applicable types+-- found on Cabal. Exceptions: utf8-string, ListLike, IxSet++test-suite test+ type: exitcode-stdio-1.0+ main-is: main.hs+ hs-source-dirs: test,src+ build-depends: base >= 4.5 && < 4.8+ , base-compat >= 0.5 && < 0.6+ , containers >= 0.5 && < 0.6+ , text >= 0.11.3 && < 1.3+ , unordered-containers >= 0.2.3+ , vector >= 0.10.0.1+ , text >= 0.11.3.1+ , bytestring >= 0.10.0.2+ , system-filepath >= 0.4.6+ , QuickCheck >= 2.6+ , quickcheck-instances >= 0.3.5 + , HUnit >= 1.2.5.2+ , hspec >= 1.7.2+ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/jcristovao/IsNull
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, João Cristóvão++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of João Cristóvão nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,61 @@+IsNull+======++A typeclass to determine if a given container is null.++Strongly inspired by +[mono-traversable](https://hackage.haskell.org/package/mono-traversable), +but with a simpler goal: supporting IsNull and nested IsNull operations.++Supported functions:++```+isNull :: a -> Bool++notNull :: a -> Bool++-- | Nested isNull+isNullN :: (Foldable f) => f a -> Bool++-- | Monadic isNull+isNullM :: Monad m => m a -> m Bool++-- | Monadic Nested isNull+isNullNM :: (Monad m, Foldable f) => m (f a) -> m Bool+++-- | Alternative <|> operator does not always operate as choice,+-- at least not in an intuitive way (for example with lists).+-- This one does:+<\> :: a -> a -> a+```++The N stands for (non-recursive) nested, such that:++```++isNullN (Just "abc") == False+isNullN (Just "" ) == True+isNullN (Nothing ) == True++```++While the ```isNull``` function is equivalent to ```(==) mempty```+for most of the instances, not all ```Foldable```s are monoids,+and not all monoids ```mempty``` means null:++* ```Either``` is an example of a ```Foldable``` which is not a+ ```Monoid```, but where it makes sense to consider a ```Left``` as+ an 'Null' value. While this is not strictly true, the ```Left```+ option does carries a value, we take the more liberal approach:+ Empty ~ Null ~ Invalid Value.+ If you need proper type reasoning, you should not be using this+ package, just regular pattern matching instead.++* ```Product``` ```Monoid``` instance is ```1```. Hardly qualifies as an+ ```Empty``` or ```Null``` value. For this reason no default implementation+ is provided for the ```Monoid``` class. It's up to you to use+ ```(==) mempty``` instead.+++Bugs, suggestions and comments are most welcomed!
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Data/IsNull.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE IncoherentInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++{- |+Module: IsNull+Description: A typeclass to determine if a given value is null.+Copyright: João Cristóvão, 2014+License: BSD3+Maintainer: jmacristovao@gmail.com++A typeclass to determine if a given value is null.++Strongly inspired by+<https://hackage.haskell.org/package/mono-traversable mono-traversable>+but with a simpler goal: supporting IsNull and nested IsNull operations.++While the @'isNull'@ function is equivalent to @(==) mempty@ for most of+the instances, not all @'Foldable'@s are monoids,+and not all monoids @'mempty'@ means null:++* @'Either'@ is an example of a @Foldable@ which is not a+ @'Monoid'@, but where it makes sense to consider a @'Left'@ as+ an 'Null' value. While this is not strictly true, the @'Left'@+ option does carries a value, we take the more liberal approach:+ Empty ~ Null ~ Invalid Value.+ If you need proper type reasoning, you should not be using this+ package, just regular pattern matching instead.++* @'Product'@ @'Monoid'@ instance is @1@. Hardly qualifies as an+ @Empty@ or @Null@ value. For this reason no default implementation+ is provided for the @'Monoid'@ class. It's up to you to use+ @(==) mempty@ instead.++The main use case for this package are boolean conditions,+namely the @if@ @then@ @else@ construct.++Bugs, suggestions and comments are most welcomed!++<https://github.com/jcristovao/IsNull>++-}+module Data.IsNull (+ IsNull(..)+) where+++import Data.IsNull.Internal++
+ src/Data/IsNull/Internal.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Data.IsNull.Internal where++import qualified Data.Foldable.Compat as F+import qualified Data.Text as T+import qualified Data.Text.Lazy as LT+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as LBS+import qualified Data.IntSet as IS+import Control.Monad (liftM)+++class IsNull a where+ -- | isNull ~ isEmpty ~ isInvalid?+ --+ -- >>> isNull (Left 5)+ -- True+ --+ -- >>> isNull ("abc" :: T.Text)+ -- False+ --+ -- >>> isNull [""] -- see isNullN+ -- False+ isNull:: a -> Bool++ -- | Typing causes arthritis. Alias for @'isNull'@.+ isN :: a -> Bool+ isN = isNull++ -- | the logical negation of @'isNull'@+ notNull :: a -> Bool+ notNull = not . isNull++ -- | Nested isNull+ --+ -- >>> isNullN (Just "abc")+ -- False+ --+ -- >>> isNullN (Just "")+ -- True+ --+ -- >>> isNullN (Nothing :: Maybe String)+ -- True+ isNullN :: F.Foldable f => f a -> Bool+ isNullN = F.all isNull++ -- | Nested isNotNull+ notNullN :: F.Foldable f => f a -> Bool+ notNullN = not . isNullN++ -- | Monadic isNull+ --+ -- >>> isNullM [""]+ -- [True]+ isNullM :: Monad m => m a -> m Bool+ isNullM = liftM isNull++ -- | Monadic Nested isNull+ isNullNM :: (Monad m, F.Foldable f) => m (f a) -> m Bool+ isNullNM = liftM isNullN++ -- | @'Alternative'@'s @'<|>'@ operator does not always operate as choice,+ -- at least not in an intuitive way (for example with lists).+ -- This one does:+ --+ -- >>> [2,3] <\> [4,5]+ -- [2,3]+ --+ -- >>> [] <\> [4,5]+ -- [4,5]+ --+ -- >>> [] <\> []+ -- []+ (<\>) :: a -> a -> a+ (<\>) a b = if isNull a then b else a+ infixl 3 <\>++instance IsNull Bool where+ isNull = not++instance IsNull T.Text where+ isNull = T.null++instance IsNull LT.Text where+ isNull = LT.null++instance IsNull BS.ByteString where+ isNull = BS.null++instance IsNull LBS.ByteString where+ isNull = LBS.null++instance IsNull IS.IntSet where+ isNull = IS.null++instance F.Foldable f => IsNull (f a) where+ isNull = F.foldr (\_ _ -> False) True+
+ test/main.hs view
@@ -0,0 +1,2 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}+