diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -24,8 +24,16 @@
    = Example
    { ex_username :: T.Text
    , ex_dogs :: Int
+   , ex_friendName :: Maybe T.Text
    } deriving (Show)
 
+data ExampleChecked
+   = ExampleChecked
+   { exc_username :: T.Text
+   , exc_dogs :: Int
+   , exc_friendName :: T.Text
+   } deriving (Show)
+
 main :: IO ()
 main =
     do putStrLn "Check results:"
@@ -40,17 +48,20 @@
 checkNumber =
     smallerThan 5 "No more than 5 dogs allowed"
 
-checkExample :: Monad m => ValidationRuleT String m Example
+checkExample :: Monad m => TransValidationRuleT String m Example ExampleChecked
 checkExample e =
-    Example <$> checkUsername (ex_username e)
-            <*> checkNumber (ex_dogs e)
+    ExampleChecked
+    <$> checkUsername (ex_username e)
+    <*> checkNumber (ex_dogs e)
+    <*> requiredValue "You must provide a friend name!" (ex_friendName e)
 
-example :: Either String Example
+example :: Either String ExampleChecked
 example =
     runValidator checkExample $
     Example
     { ex_username = "alex"
     , ex_dogs = 23
+    , ex_friendName = Nothing
     }
 
 ```
diff --git a/src/Data/Validator.hs b/src/Data/Validator.hs
--- a/src/Data/Validator.hs
+++ b/src/Data/Validator.hs
@@ -4,7 +4,9 @@
 {-# LANGUAGE OverloadedStrings #-}
 module Data.Validator
     ( -- * Core monad and runners
-      ValidationM, ValidationT, ValidationRule, ValidationRuleT
+      ValidationM, ValidationT
+    , ValidationRule, ValidationRuleT
+    , TransValidationRule, TransValidationRuleT
     , runValidator, runValidatorT
       -- * Combinators
     , (>=>), (<=<)
@@ -13,6 +15,9 @@
     , largerThan, smallerThan, valueBetween
     , matchesRegex
     , conformsPred, conformsPredM
+      -- * Transforming checks
+    , requiredValue, nonEmptyList
+    , conformsPredTrans, conformsPredTransM
       -- * Helper classes and types
     , HasLength(..), ConvertibleStrings(..)
     , Int64
@@ -29,6 +34,7 @@
 import Data.Int
 import Data.String.Conversions
 import Text.Regex.PCRE.Heavy
+import qualified Data.List.NonEmpty as NEL
 import qualified Data.Text as T
 import qualified Data.Text.Lazy as TL
 import qualified Data.ByteString as BS
@@ -43,12 +49,12 @@
       deriving (Monad, Functor, Applicative, Alternative, MonadPlus, MonadTrans)
 
 -- | Run a validation on a type 'a'
-runValidator :: ValidationRule e a -> a -> Either e a
+runValidator :: TransValidationRule e a b -> a -> Either e b
 runValidator a b = runIdentity $ runValidatorT a b
 {-# INLINE runValidator #-}
 
 -- | Run a validation on a type 'a'
-runValidatorT :: Monad m => ValidationRuleT e m a -> a -> m (Either e a)
+runValidatorT :: Monad m => TransValidationRuleT e m a b -> a -> m (Either e b)
 runValidatorT validationSteps input =
     runEitherT $ unValidationT (validationSteps input)
 {-# INLINE runValidatorT #-}
@@ -57,8 +63,14 @@
 type ValidationRule e a = ValidationRuleT e Identity a
 
 -- | A validation rule. Combine using @('>=>')@ or @('<=<')@
-type ValidationRuleT e m a = a -> ValidationT e m a
+type ValidationRuleT e m a = TransValidationRuleT e m a a
 
+-- | A transforming validation rule. Combine using @('>=>')@ or @('<=<')@
+type TransValidationRule e a b = TransValidationRuleT e Identity a b
+
+-- | A transforming validation rule. Combine using @('>=>')@ or @('<=<')@
+type TransValidationRuleT e m a b = a -> ValidationT e m b
+
 -- | All types that have a length, eg. 'String', '[a]', 'Vector a', etc.
 class HasLength a where
     getLength :: a -> Int64
@@ -124,6 +136,11 @@
 valueBetween lowerBound upperBound e = largerThan lowerBound e >=> smallerThan upperBound e
 {-# INLINE valueBetween #-}
 
+-- | Checks that a value matches a regular expression
+matchesRegex :: (ConvertibleStrings SBS a, ConvertibleStrings a SBS, Monad m) => Regex -> e -> ValidationRuleT e m a
+matchesRegex r = conformsPred (=~ r)
+{-# INLINE matchesRegex #-}
+
 -- | Check that a value conforms a predicate
 conformsPred :: Monad m => (a -> Bool) -> e -> ValidationRuleT e m a
 conformsPred predicate e obj = unless (predicate obj) (checkFailed e) >> return obj
@@ -136,7 +153,29 @@
        unless res (checkFailed e) >> return obj
 {-# INLINE conformsPredM #-}
 
--- | Checks that a value matches a regular expression
-matchesRegex :: (ConvertibleStrings SBS a, ConvertibleStrings a SBS, Monad m) => Regex -> e -> ValidationRuleT e m a
-matchesRegex r = conformsPred (=~ r)
-{-# INLINE matchesRegex #-}
+-- | Check that an optional value is actually set to 'Just a'
+requiredValue :: Monad m => e -> TransValidationRuleT e m (Maybe a) a
+requiredValue = conformsPredTrans id
+{-# INLINE requiredValue #-}
+
+-- | Check that a list is not empty
+nonEmptyList :: Monad m => e -> TransValidationRuleT e m [a] (NEL.NonEmpty a)
+nonEmptyList = conformsPredTrans NEL.nonEmpty
+{-# INLINE nonEmptyList #-}
+
+-- | Do some check returning 'Nothing' if the value is invalid and 'Just a' otherwise.
+conformsPredTrans :: Monad m => (a -> Maybe b) -> e -> TransValidationRuleT e m a b
+conformsPredTrans f e obj =
+    case f obj of
+      Nothing -> checkFailed e
+      Just val -> return val
+{-# INLINE conformsPredTrans #-}
+
+-- | Do some check returning 'Nothing' if the value is invalid and 'Just a' otherwise.
+conformsPredTransM :: Monad m => (a -> m (Maybe b)) -> e -> TransValidationRuleT e m a b
+conformsPredTransM f e obj =
+    do res <- lift $ f obj
+       case res of
+         Nothing -> checkFailed e
+         Just val -> return val
+{-# INLINE conformsPredTransM #-}
diff --git a/validate-input.cabal b/validate-input.cabal
--- a/validate-input.cabal
+++ b/validate-input.cabal
@@ -1,5 +1,5 @@
 name:                validate-input
-version:             0.3.0.0
+version:             0.4.0.0
 synopsis:            Input validation combinator library
 description:         A small Haskell combinator library that provides a simple way of
                      validating user provided data structures.
@@ -32,6 +32,7 @@
                        mtl >=2.1,
                        pcre-heavy >=1.0,
                        string-conversions >=0.4,
+                       semigroups >=0.16,
                        text >=1.2
   hs-source-dirs:      src
   default-language:    Haskell2010
