diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,7 @@
+0.0.2
+
+* Add combinators for processing bank transactions
+
 0.0.1
 
 * This change log starts
diff --git a/national-australia-bank.cabal b/national-australia-bank.cabal
--- a/national-australia-bank.cabal
+++ b/national-australia-bank.cabal
@@ -1,5 +1,5 @@
 name:                 national-australia-bank
-version:              0.0.1
+version:              0.0.2
 synopsis:             Functions for National Australia Bank transactions
 description:          Parsing, Processing and other functions for National Australia Bank transactions
 license:              BSD3
@@ -21,10 +21,12 @@
 
 library
   exposed-modules:
+                      Data.Bank.Combinators
                       Data.Bank.NationalAustraliaBank.NationalAustraliaBank
 
   build-depends:        base                 >= 4.9 && < 4.15
                       , bytestring           == 0.10.8.2
+                      , containers           == 0.6.0.1
                       , digit                == 0.12
                       , directory            == 1.3.6.1
                       , filepath             == 1.4.2.1
diff --git a/src/Data/Bank/Combinators.hs b/src/Data/Bank/Combinators.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Bank/Combinators.hs
@@ -0,0 +1,142 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE FlexibleContexts #-}
+
+module Data.Bank.Combinators where
+
+import Control.Applicative (Applicative(liftA2))
+import Control.Category (Category(..) )
+import Control.Lens
+    ( _Left,
+      isn't )
+import Control.Monad.State
+    ( Monad((>>=)) )
+import Data.Bool(bool)
+import qualified Data.List as List ( isInfixOf )
+import Data.Functor( Functor(..) )
+import Data.Functor.Identity ( Identity(..) )
+import Data.Set(Set)
+import qualified Data.Set as Set(singleton)
+import Data.List.NonEmpty ( some1 )
+import Text.Parsec
+    ( char,
+      noneOf,
+      string,
+      eof,
+      parse,
+      try,
+      Parsec,
+      ParsecT,
+      Stream )
+import Prelude hiding (id, (.) )
+
+contains ::
+  (Eq a, Functor f) =>
+  [a]
+  -> f [a]
+  -> f Bool
+contains =
+  fmap . List.isInfixOf
+
+equals ::
+  (Eq a, Functor f) =>
+  a
+  -> f a
+  -> f Bool
+equals =
+  fmap . (==)
+
+(~~) ::
+  a
+  -> (a -> b)
+  -> b
+a ~~ f =
+  f a
+
+infixl 8 ~~
+
+(~>) ::
+  (Functor f, Monoid c) =>
+  f Bool
+  -> c
+  -> f c
+b ~> c =
+  fmap (bool mempty c) b
+
+infixr 7 ~>
+
+(~>>) ::
+  (Ord c, Functor f) =>
+  f Bool
+  -> c
+  -> f (Set c)
+b ~>> c =
+  b ~> Set.singleton c
+
+infixl 7 ~>>
+
+parses ::
+  (Functor f, Stream s Identity t) =>
+  Parsec s () c
+  -> f s
+  -> f Bool
+parses p =
+  fmap (isn't _Left . parse (try p) "parses")
+
+parenthesisedParser ::
+  Stream s m Char =>
+  String
+  -> ParsecT s u m ()
+parenthesisedParser s =
+  string s *> string " (" *> some1 (noneOf ")") *> char ')' *> eof
+
+parenthesised ::
+  (Functor f, Stream s Identity Char) =>
+  String
+  -> f s
+  -> f Bool
+parenthesised =
+  parses . parenthesisedParser
+
+(...) ::
+  (Monad f, Foldable g) =>
+  (a -> f a -> f Bool)
+  -> g a
+  -> (f a -> f Bool)
+f ... t =
+  \x ->
+    foldr (\a b -> f a x .||. b) (pure False) t
+
+infixl 9 ...
+
+(.||.) ::
+  Monad f =>
+  f Bool
+  -> f Bool
+  -> f Bool
+p .||. q =
+  p >>= bool q (pure True)
+
+(.|||.) ::
+  (Applicative f, Applicative g, Monad h) =>
+  f (g (h Bool))
+  -> f (g (h Bool))
+  -> f (g (h Bool))
+(.|||.) =
+  liftA2 (liftA2 (.||.))
+
+(.&&.) ::
+  Monad f =>
+  f Bool
+  -> f Bool
+  -> f Bool
+p .&&. q =
+  p >>= bool (pure False) q
+
+(.&&&.) ::
+  (Applicative f, Applicative g, Monad h) =>
+  f (g (h Bool))
+  -> f (g (h Bool))
+  -> f (g (h Bool))
+(.&&&.) =
+  liftA2 (liftA2 (.&&.))
