diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,5 @@
+# Revision history for data-filter
+
+## 0.1.0.0  -- 2018-05-17
+
+* First version. Released on an unsuspecting world.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,26 @@
+Copyright (c) 2018, Sophie Hirn
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. 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.
+
+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,3 @@
+# data-filter
+
+Utilities for filtering. See the documentation of `Data.Filter` for more info.
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/data-filter.cabal b/data-filter.cabal
new file mode 100644
--- /dev/null
+++ b/data-filter.cabal
@@ -0,0 +1,32 @@
+name:                data-filter
+version:             0.1.0.0
+synopsis:            Utilities for filtering
+homepage:            https://github.com/LadyBoonami/data-filter
+license:             BSD2
+license-file:        LICENSE
+author:              Sophie Hirn
+maintainer:          sophie.hirn@wyvernscale.com
+copyright:           (c) 2018 Sophie Hirn
+category:            Data
+build-type:          Simple
+extra-source-files:  ChangeLog.md, README.md
+cabal-version:       >=1.10
+
+description:
+  Some helpers to make using Prelude.filter and similar value selection a bit
+  easier. Includes combinators for predicates as well as an operator to match
+  the constructor used for the given value.
+
+source-repository head
+  type:     git
+  location: https://github.com/LadyBoonami/data-filter
+
+library
+  hs-source-dirs:      src
+  default-language:    Haskell2010
+  build-depends:
+    base         < 5,
+    data-default < 1
+
+  exposed-modules:
+    Data.Filter
diff --git a/src/Data/Filter.hs b/src/Data/Filter.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Filter.hs
@@ -0,0 +1,203 @@
+{-# LANGUAGE DeriveFunctor
+           , DeriveGeneric
+           , FlexibleContexts
+           , FlexibleInstances
+           , FunctionalDependencies
+           , KindSignatures
+           , MultiParamTypeClasses
+           , ScopedTypeVariables
+           , TypeOperators
+           , TypeSynonymInstances
+           , UndecidableInstances
+           #-}
+
+{-|
+Module      : Data.Filter
+Description : Utilities for filtering
+Copyright   : (c) Sophie Hirn, 2018
+License     : BSD2
+Maintainer  : sophie.hirn@wyvernscale.com
+
+Some helpers to make using Prelude.filter and similar value selection a bit
+easier. Includes combinators for predicates as well as an operator to match
+the constructor used for the given value.
+-}
+
+module Data.Filter
+    ( -- * Constructors
+      -- | The @(=?=)@-operator can be used to check whether two values were
+      --   generated using the same constructor. For this to work, the
+      --   underlying data type must instantiate 'GHC.Generics.Generic',
+      --   parameters to the constructor can additionally be left out if their
+      --   type implements 'ReduceWith'.
+      constrName
+    , HasConstructor (..)
+      -- * Reduction
+      -- | Constructors can be /reduced/ to values by passing them arbitrary
+      --   arguments. The actual value of those does not impact the result of
+      --   the @(=?=)@-operator. For lazy members, passing 'undefined' works
+      --   just fine, but putting 'undefined' into strict fields causes carnage.
+      --   'ReduceWith' provides arbitrary values, deriving from `Default` where
+      --   possible.
+    , ReduceWith (..)
+    , Reduce (..)
+      -- * Operators
+    , (=?=)
+    , (==>)
+    , (<||>)
+    , any_
+    , (<&&>)
+    , all_
+      -- * Matching Wrappers
+    , Infinite (..)
+      -- * Useful functions from other modules
+    , mapMaybe
+    ) where
+
+
+import Control.Monad
+import Data.Default
+import Data.List
+import Data.Maybe
+import GHC.Generics
+
+
+
+-- | Retrieve the constructor name of the given value as a string. This
+--   implementation is taken from https://stackoverflow.com/questions/48179380/getting-the-data-constructor-name-as-a-string-using-ghc-generics .
+constrName :: (HasConstructor (Rep a), Generic a) => a -> String
+constrName = genericConstrName . from
+
+-- | Automatically derived from 'Generic' instances.
+class HasConstructor (f :: * -> *) where
+    genericConstrName :: f x -> String
+
+instance HasConstructor f => HasConstructor (D1 c f) where
+    genericConstrName (M1 x) = genericConstrName x
+
+instance (HasConstructor x, HasConstructor y) => HasConstructor (x :+: y) where
+    genericConstrName (L1 l) = genericConstrName l
+    genericConstrName (R1 r) = genericConstrName r
+
+instance Constructor c => HasConstructor (C1 c f) where
+    genericConstrName x = conName x
+
+-- end from
+
+
+
+-- | Type that can be reduced away from a constructor. Use this to make your
+--   data types compatible. The reduction process and the @(=?=)@-operator do
+--   not evaluate fields, therefore creating an empty instance which defaults to
+--   @'reduceWith' = 'undefined'@ is okay __as long as no reduced field of__
+--   __this type is strict__.
+class ReduceWith a where
+    reduceWith :: a
+    reduceWith = undefined
+
+instance {-# OVERLAPPING  #-} ReduceWith Bool where
+    reduceWith = True
+
+instance {-# OVERLAPPING  #-} ReduceWith Char where
+    reduceWith = ' '
+
+instance {-# OVERLAPPABLE #-} (Default a) => ReduceWith a where
+    reduceWith = def
+
+
+
+-- | Reduction of a constructor @a -> ... -> c@ to a value of type @c@.
+class (HasConstructor (Rep c), Generic c) => Reduce a c | a -> c where
+    reduce :: a -> c
+
+instance {-# OVERLAPPABLE #-} (HasConstructor (Rep a), Generic a) => Reduce a a where
+    reduce = id
+
+instance {-# OVERLAPPABLE #-} (ReduceWith a, Reduce b c) => Reduce (a -> b) c where
+    reduce = reduce . ($ reduceWith)
+
+
+
+-- | Checks whether two values are created by the same data constructor. Also
+--   works with constructors that have not yet received all their arguments.
+--   This allows for very convenient constructs, e.g.:
+--
+-- >>> Just 1 =?= Just
+-- True
+--
+-- >>> Just 1 =?= Nothing
+-- False
+--
+-- >>> let filterJust = filter (=?= Just)
+-- >>> filterJust [Just 1, Nothing, Just 9001]
+-- [Just 1, Just 9001]
+--
+-- >>> let filterJust_ = mapMaybe $ (=?= Just) ==> fromJust
+-- >>> filterJust_ [Just 1, Nothing, Just 9001]
+-- [1, 9001]
+--
+-- >>> let over9000 = mapMaybe $ ((=?= Just) <&&> (>9000) . fromJust) ==> fromJust
+-- >>> over9000 [Just 1, Nothing, Just 9001]
+-- [9001]
+(=?=) :: (Reduce a c, Reduce b c) => a -> b -> Bool
+infixl 4 =?=
+(=?=) a b = constrName (reduce a) == constrName (reduce b)
+
+
+
+-- | @(pred ==> f) x@ returns @'Just' (f x)@ if @pred x@ succeeds and
+--   @'Nothing'@ otherwise.
+(==>) :: (a -> Bool) -> (a -> b) -> a -> Maybe b
+(==>) p f x = if p x then Just $ f x else Nothing
+
+
+
+(<||>) :: (a -> Bool) -> (a -> Bool) -> a -> Bool
+infixl 2 <||>
+(<||>) = liftM2 (||)
+
+any_ :: [a -> Bool] -> a -> Bool
+any_ = foldl' (<||>) $ const False
+
+(<&&>) :: (a -> Bool) -> (a -> Bool) -> a -> Bool
+infixl 3 <&&>
+(<&&>) = liftM2 (&&)
+
+all_ :: [a -> Bool] -> a -> Bool
+all_ = foldl' (<&&>) $ const True
+
+
+
+-- | Adds negative and positive infinity to an ordered type. The 'fromEnum'
+--   function is inherently susceptible to overflow since the class 'Enum' is
+--   defined using 'Int' instead of 'Integer', but this should not cause trouble
+--   with \"small\" enums.
+data Infinite a
+    = NegInfin
+    | Exact !a
+    | PosInfin
+    deriving (Eq, Functor, Read, Show, Ord, Generic)
+
+instance (Eq a, Bounded a, Enum a) => Enum (Infinite a) where
+    fromEnum NegInfin  = fromEnum (minBound :: a) - 1
+    fromEnum (Exact x) = fromEnum x
+    fromEnum PosInfin  = fromEnum (maxBound :: a) + 1
+
+    toEnum x | x == fromEnum (minBound :: a) - 1 = NegInfin
+             | x == fromEnum (maxBound :: a) + 1 = PosInfin
+             | otherwise                         = Exact $ toEnum x
+
+    succ NegInfin = Exact minBound
+    succ PosInfin = PosInfin
+    succ (Exact x)
+        | x == maxBound = PosInfin
+        | otherwise     = Exact $ succ x
+
+    pred NegInfin = NegInfin
+    pred PosInfin = Exact maxBound
+    pred (Exact x)
+        | x == minBound = NegInfin
+        | otherwise     = Exact $ pred x
+
+instance (Default a) => Default (Infinite a) where
+    def = Exact def
