diff --git a/IsNull.cabal b/IsNull.cabal
new file mode 100644
--- /dev/null
+++ b/IsNull.cabal
@@ -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
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -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!
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/src/Data/IsNull.hs b/src/Data/IsNull.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/IsNull.hs
@@ -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
+
+
diff --git a/src/Data/IsNull/Internal.hs b/src/Data/IsNull/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/IsNull/Internal.hs
@@ -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
+
diff --git a/test/main.hs b/test/main.hs
new file mode 100644
--- /dev/null
+++ b/test/main.hs
@@ -0,0 +1,2 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+
