diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,6 +1,35 @@
 # ChangeLog / ReleaseNotes
 
 
+## Version 0.3.0.0
+
+* Introducing type `:->` to simplify type signatures of endomorphism folding
+  functions that restrict type of a result. (**new**)
+* Type class `AnEndo` moved in to a separate module `Data.Monoid.Endo.AnEndo`.
+  Definitions are reexported by `Data.Monoid.Endo.Fold`, therefore providing
+  backward compatible API. (**change**)
+* Introducing `instance AnEndo a => AnEndo (Identity a)`. (**new**)
+* Introducing `FromEndo` type class for conversion of endomorphism in to a
+  value. It is a dual to `AnEndo` type class. This type class resides in its
+  own module `Data.Monoid.Endo.FromEndo`. (**new**)
+* Introducing `ApplyEndo` newtype that provides easier endomorphism evaluation
+  in cases when there is an "obvious" default value. This type has its own
+  module `Data.Monoid.Endo.Apply` that also provides various helper functions
+  and type class instances. (**new**)
+* Providing `Eq1`, `Ord1`, `Read1` and `Show1` instances if built with
+  [transformers package][transformers] >=0.5 or base >=4.9 (i.e. GHC
+  >=8.0.1) is available. (**new**)
+* Providing `Generic1` instance for `WrappedFoldable`. (**new**)
+* Introducing `instance AnEndo a => AnEndo (Option a)`, but only when compiled
+  with base >=4.9, since that is the first version of base which contains
+  `Semigroup`. (**new**)
+* Bumped upper bound of [transformers package][transformers] to include 0.5.\*
+  versions. (**change**)
+* Synchronized API documentation of `Data.Monoid.Endo.Fold` with README.
+  (**trivial change**)
+* Uploaded to [Hackage][]: <http://hackage.haskell.org/package/endo-0.3.0.0>
+
+
 ## Version 0.2.0.1
 
 * API documentation ehancements and clarifications.
@@ -14,13 +43,13 @@
 * Default implementation for `anEndo` method of 'AnEndo' type class, which is
   now defined as: `anEndo = getDual . aDualEndo`. As a consequence it is now
   possible to define complete instances of `AnEndo` by providing either
-  `anEndo` or `aDualEndo`. (new, change)
+  `anEndo` or `aDualEndo`. (**new**, **change**)
 * Introducing associated type `Result` to `FoldEndoArgs` type class. This
   allows result of the whole folding to be explicitly stated in a type
-  signature. (new, change)
+  signature. (**new**, **change**)
 * Introducing functions `embedEndoWith` and `embedDualEndoWith`. Both can be
   used to simplify application of endomorphisms that are result of folding.
-  (new)
+  (**new**)
     - `embedEndoWith :: (AnEndo e, EndoOperatesOn e ~ a) => (Endo a -> b) -> e
       -> b`
     - `embedDualEndoWith :: (AnEndo e, EndoOperatesOn e ~ a) => (Dual (Endo a)
@@ -28,19 +57,19 @@
 * Introducing `instance AnEndo (Proxy a)`, which is useful in cases when one
   needs to force constraint `EndoOperatesOn args ~ a` where `a` is the `a` from
   `Proxy a`. This is done by encoding value of `Proxy` in to identity
-  endomorphism that operates on specified type `a`. (new)
+  endomorphism that operates on specified type `a`. (**new**)
 * Introducing `instance (Monoid c, FoldEndoArgs r) => FoldEndoArgs (Const c
   r)`, which is useful in cases when one needs to discard the computation and
-  return a constant instead. (new)
+  return a constant instead. (**new**)
 * Bumping upper bounds on base and between, therefore it now builds on GHC 7.10
-  with base 4.8. (new)
+  with base 4.8. (**new**)
 * Uploaded to [Hackage][]: <http://hackage.haskell.org/package/endo-0.2.0.0>
 
 
 ## Version 0.1.0.2
 
 * Bugfix release.
-* Bugfix: Unable to compile with transformers >= 0.4 (again).
+* Bugfix: Unable to compile with [transformers][] >= 0.4 (again).
 * Minor documentation updates.
 * Uploaded to [Hackage][]: <http://hackage.haskell.org/package/endo-0.1.0.2>
 
@@ -48,13 +77,13 @@
 ## Version 0.1.0.1
 
 * Bugfix release.
-* Bugfix: Unable to compile with transformers >= 0.4.
+* Bugfix: Unable to compile with [transformers][] >= 0.4.
 * Uploaded to [Hackage][]: <http://hackage.haskell.org/package/endo-0.1.0.1>
 
 
 ## Version 0.1.0.0
 
-* **This version doesn't work with transformers >= 0.4.**
+* **This version doesn't work with [transformers][] >= 0.4.**
 * First public release.
 * Uploaded to [Hackage][]: <http://hackage.haskell.org/package/endo-0.1.0.0>
 
@@ -63,6 +92,9 @@
 [Hackage]:
   http://hackage.haskell.org/
   "HackageDB (or just Hackage) is a collection of releases of Haskell packages."
+[transformers]:
+  https://hackage.haskell.org/package/transformers
+  "Package transformers on Hackage."
 
 <!--
   vim: filetype=markdown softtabstop=4 shiftwidth=4 expandtab
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2013-2015, Peter Trško
+Copyright (c) 2013-2016, Peter Trško
 
 All rights reserved.
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -15,6 +15,12 @@
 
 ## Usage Examples
 
+Examples in this section were taken from real live production code, but they
+were tamed down a little.
+
+
+### Basic Idea
+
 Lets define simple application `Config` data type as:
 
 ````Haskell
@@ -56,14 +62,20 @@
 ````
 
 Above example shows us that it is possible to modify `Config` as if it was a
-monoid, but without actually having to state it as such. In practice it is
-not always possible to define it as `Monoid` or at least a `Semigroup`. What
-usually works are endomorphisms, like in this example.
+monoid, but without actually having to state it as such. In practice it is not
+always possible to define it as `Monoid`, or at least as a `Semigroup`.
+Endomorphism are monoids under composition, therefore they are what usually
+works in situations when the modified data type can not be instantiated as a
+monoid.
 
-Now, `FilePath` has one pathological case, and that is `""`. There is a lot of
-ways to handle it. Here we will concentrate only few basic techniques to
-illustrate versatility of our approach.
 
+### Working With Corner Cases
+
+In real applications corner cases arise quite easily, e.g. `FilePath` has one
+pathological case, and that is `""`. There is a lot of ways to handle it. Here
+we will concentrate only few basic techniques to illustrate versatility of our
+approach.
+
 ````Haskell
 -- | Trying to set output file to \"\" will result in keeping original value.
 setOutputFile2 :: FilePath -> E Config
@@ -88,7 +100,15 @@
     &$ setVerbosity Annoying
     &$ setOutputFile3 "an.out.put"
 ````
+Great thing about `Maybe` is the fact that it has `Alternative` and `MonadPlus`
+instances. Using `guard` may simplify `setOutputFile3` in to definition like
+following:
 
+````Haskell
+setOutputFile3':: FilePath -> Maybe (E Config)
+setOutputFile3' fp = setOutputFile fp <$ guard (not (null fp))
+````
+
 Following example uses common pattern of using `Either` as error reporting
 monad. This approach can be easily modified for arbitrary error reporting
 monad.
@@ -109,9 +129,12 @@
 constructor arguments and order of operations. Using `foldEndo` (and its
 dual `dualFoldEndo`) doesn't have this restriction.
 
-Instead of setter functions one may want to use lenses (in terms of
-[lens package][Hackage: lens]):
+### Lenses
 
+Instead of setter functions one may want to use lenses. In this example we use
+types from [lens package][Hackage: lens], but definitions use function from
+[between package][Hackage: between]:
+
 ````Haskell
 verbosity :: Lens' Config Verbosity
 verbosity = _verbosity ~@@^> \s b -> s{_verbosity = b}
@@ -129,6 +152,8 @@
     &$ outputFile .~ "an.out.put"
 ````
 
+### Other Usage
+
 Probably one of the most interesting things that can be done with this
 module is following:
 
@@ -248,6 +273,12 @@
   Pass additional warning flags to GHC.
 
 
+License
+-------
+
+The BSD 3-Clause License, see [LICENSE][] file for details.
+
+
 ## Contributions
 
 Contributions, pull requests and bug reports are welcome! Please don't be
@@ -255,6 +286,9 @@
 
 
 
+[Hackage: between]:
+  http://hackage.haskell.org/package/between
+  "between package on Hackage"
 [Hackage: endo]:
   http://hackage.haskell.org/package/endo
   "endo package on Hackage"
@@ -267,6 +301,9 @@
 [Haskell.org]:
   http://www.haskell.org
   "The Haskell Programming Language"
+[LICENSE]:
+  https://github.com/trskop/endo/blob/master/LICENSE
+  "License of endo package."
 [tl;dr Legal: BSD3]:
   https://tldrlegal.com/license/bsd-3-clause-license-%28revised%29
   "BSD 3-Clause License (Revised)"
diff --git a/endo.cabal b/endo.cabal
--- a/endo.cabal
+++ b/endo.cabal
@@ -1,5 +1,5 @@
 name:                   endo
-version:                0.2.0.1
+version:                0.3.0.0
 synopsis:               Endomorphism utilities.
 description:
   Package defines extra functions for 'Data.Monoid.Endo' data type, and also
@@ -46,11 +46,14 @@
 license-file:           LICENSE
 author:                 Peter Trško
 maintainer:             peter.trsko@gmail.com
-copyright:              (c) 2013-2015, Peter Trško
+copyright:              (c) 2013-2016, Peter Trško
 category:               Data
 build-type:             Simple
 cabal-version:          >=1.10
 
+-- See https://github.com/trskop/endo/blob/master/.travis.yml for more details.
+tested-with:            GHC ==7.6.3, GHC ==7.8.4, GHC ==7.10.3, GHC ==8.0.1
+
 -- Examples require lens and optparse-applicative packages in addition to this
 -- packackage's dependencies. When using sandbox it is possible to use "cabal
 -- repl" to test examples by using following command:
@@ -76,7 +79,10 @@
   hs-source-dirs:       src
   exposed-modules:
       Data.Monoid.Endo
+    , Data.Monoid.Endo.AnEndo
+    , Data.Monoid.Endo.Apply
     , Data.Monoid.Endo.Fold
+    , Data.Monoid.Endo.FromEndo
 
   default-language:     Haskell2010
   other-extensions:
@@ -88,18 +94,47 @@
 
   build-depends:
     -- {{{ Distributed with GHC or Haskell Platform ---------------------------
-      base >=4.6 && <4.9
-    , transformers >=0.3 && <0.5
+      base >=4.6 && <5
+    , transformers >=0.3 && <0.6
+    , mtl >=2.1 && <3
+    -- ^ Version 2.1 is the first that supported transformers ==0.3, which is
+    -- the lowest supported version by this package.
+
     -- }}} Distributed with GHC or Haskell Platform ---------------------------
 
-    , between >=0.9 && <0.11
+    , between >=0.9 && <1
+    , data-default-class ==0.0.*
 
-  if impl(GHC >= 7.8)
-    cpp-options:        -DHAVE_MINIMAL_PRAGMA
-                        -DKIND_POLYMORPHIC_TYPEABLE
-  if impl(GHC >= 7.9)
-    cpp-options:        -DAPPLICATIVE_MONAD
+  if impl(GHC >=7.8)
+    cpp-options:
+      -DHAVE_KIND_POLYMORPHIC_TYPEABLE
+      -DHAVE_MINIMAL_PRAGMA
 
+      -- Module Data.Proxy, that defines Proxy data type, was
+      -- introduced in base ==4.7.0.0, i.e. GHC 7.8.1.
+      -DHAVE_PROXY
+
+  if impl(GHC >=7.10)
+    cpp-options:
+      -- Applicative became supper class of Monad in base ==4.8 which was
+      -- bundled with GHC 7.10.1 release.
+      -DHAVE_APPLICATIVE_MONAD
+
+  if impl(GHC >=8.0)
+    cpp-options:
+      -- Definition of Const moved in to its own module Data.Functor.Const in
+      -- base 4.9.0.0, i.e. GHC 8.0.1.
+      -DHAVE_FUNCTOR_CONST_MODULE
+
+      -- Module Data.Functor.Classes has moved from transformers in to base
+      -- 4.9.0.0, but the definitions in that module are compatible
+      -- only with transformers >=0.5.
+      -DHAVE_FUNCTOR_CLASSES
+
+      -- Package base ==4.9.0.0 introduces Data.Semigroup, which was originally
+      -- defined in semigroups package.
+      -DHAVE_SEMIGROUPS
+
   ghc-options:          -Wall
   if flag(pedantic)
     ghc-options:
@@ -114,4 +149,4 @@
 source-repository this
   type:                 git
   location:             git://github.com/trskop/endo.git
-  tag:                  0.2.0.1
+  tag:                  0.3.0.0
diff --git a/example/Example8.hs b/example/Example8.hs
new file mode 100644
--- /dev/null
+++ b/example/Example8.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+module Main where
+
+import Data.Functor.Identity
+
+import Data.Monoid.Endo
+import Data.Monoid.Endo.AnEndo
+
+import Data.Default.Class (Default(def))
+
+
+data Verbosity
+    = Silent
+    | Normal
+    | Verbose
+    | Annoying
+  deriving (Show {- ... -})
+
+instance Default Verbosity where
+    def = Normal
+
+class HasVerbosity s where
+    verbosity :: Functor f => (Verbosity -> f Verbosity) -> s -> f s
+
+setVerbosity :: HasVerbosity s => Verbosity -> s -> s
+setVerbosity v = runIdentity . verbosity (const (Identity v))
+
+data Config = Config
+    { cfgVerbosity :: Verbosity
+    -- ...
+    }
+  deriving (Show)
+
+instance HasVerbosity Config where
+    verbosity f cfg@Config{cfgVerbosity = v} =
+        (\v' -> cfg{cfgVerbosity = v'}) <$> f v
+
+data Action = NormalAction Config | ShowVersion | ShowHelp
+  deriving (Show {- ... -})
+
+instance Default Config where
+    def = Config
+        { cfgVerbosity = def
+        -- ...
+        }
+
+instance Default Action where
+    def = NormalAction def
+
+instance AnEndo Verbosity where
+    type EndoOperatesOn Verbosity = Action
+
+    anEndo v = Endo $ \case
+        NormalAction cfg -> NormalAction $ setVerbosity v cfg
+        action           -> action
diff --git a/example/Example9.hs b/example/Example9.hs
new file mode 100644
--- /dev/null
+++ b/example/Example9.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE FlexibleInstances #-}
+
+module Main where
+
+import Data.Functor.Identity
+
+import Data.Text (Text)
+
+import Data.Monoid.Endo
+import Data.Monoid.Endo.AnEndo
+
+import Data.Default.Class (Default(def))
+
+
+data User f g = User
+    { _login :: Text
+    , _name :: f Text
+    , _displayName :: f Text
+    , _password :: g Text
+    }
+
+type CreateUser = User Maybe Identity
+type ShowUser = User Maybe Proxy
+type AuthenticateUser = User Proxy Identity
diff --git a/src/Data/Monoid/Endo/AnEndo.hs b/src/Data/Monoid/Endo/AnEndo.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Monoid/Endo/AnEndo.hs
@@ -0,0 +1,616 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE DeriveTraversable #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE TypeFamilies #-}
+
+#ifdef HAVE_KIND_POLYMORPHIC_TYPEABLE
+{-# LANGUAGE DeriveDataTypeable #-}
+#endif
+
+#if !MIN_VERSION_base(4,9,0) && MIN_VERSION_transformers(0,5,0)
+-- Definitions in Data.Functor.Classes from transformers >=0.5 are compatible
+-- with those in base >=4.9, therefore we can enable them.
+#define HAVE_FUNCTOR_CLASSES
+#endif
+
+-- |
+-- Module:       $HEADER$
+-- Description:  Conversion of values in to endomorphisms.
+-- Copyright:    (c) 2014-2016, Peter Trško
+-- License:      BSD3
+--
+-- Maintainer:   peter.trsko@gmail.com
+-- Stability:    experimental
+-- Portability:  CPP, DeriveDataTypeable, DeriveGeneric, FlexibleInstances,
+--               NoImplicitPrelude, TypeFamilies
+--
+-- Conversion of values in to endomorphisms.
+module Data.Monoid.Endo.AnEndo
+    (
+    -- * Conversion Into Endo
+    --
+    -- | Various types can be interpreted as an encoding of an endomorphism. In
+    -- example, enum can be viewed as family of endomorphisms where each sets a
+    -- specific field of a record to a specific enum value, i.e. data
+    -- constructor. Type class 'AnEndo' provides generic way to convert values
+    -- in to an endomorphism using 'anEndo' and 'aDualEndo' functions.
+      AnEndo(..)
+
+    -- ** WrappedFoldable
+    --
+    -- $wrappedFoldable
+    , WrappedFoldable(..)
+
+    -- * Utility Functions and Types
+    , embedEndoWith
+    , embedDualEndoWith
+    )
+  where
+
+import Control.Applicative (Applicative)
+import Control.Monad (Monad)
+import Data.Foldable (Foldable(foldMap))
+import Data.Function (($), (.), id)
+import Data.Functor (Functor)
+#ifdef HAVE_FUNCTOR_CLASSES
+import Data.Functor.Classes
+    ( Eq1
+    , Ord1
+    , Read1(liftReadsPrec)
+    , Show1(liftShowsPrec)
+    , readsData
+    , readsUnaryWith
+    , showsUnaryWith
+    )
+#endif
+import Data.Functor.Identity (Identity(Identity))
+import Data.Maybe (Maybe(Just, Nothing))
+import Data.Monoid
+    ( Dual(Dual, getDual)
+    , Endo(Endo)
+    , Monoid(mempty, mconcat)
+    , (<>)
+    )
+#ifdef HAVE_SEMIGROUPS
+import Data.Semigroup (Option(Option))
+#endif
+import Data.Traversable (Traversable)
+import GHC.Generics (Generic, Generic1)
+import Text.Read (Read)
+import Text.Show (Show)
+
+#ifdef HAVE_KIND_POLYMORPHIC_TYPEABLE
+import Data.Data (Data, Typeable)
+#endif
+
+#ifdef HAVE_PROXY
+import Data.Proxy (Proxy(Proxy))
+#endif
+
+import Data.Functor.Reverse (Reverse)
+
+
+-- {{{ AnEndo Type Class ------------------------------------------------------
+
+-- | Class that represents various endomorphism representation. In other words
+-- anything that encodes @(a -> a)@ can be instance of this class.
+--
+-- Here are some important instances with not so obvious definitions.
+--
+-- @
+-- instance 'AnEndo' ('Proxy' a) where
+--     type 'EndoOperatesOn' ('Proxy' a) = a
+--
+--     'anEndo'    _ = 'mempty' -- = Endo 'id'
+--     'aDualEndo' _ = 'mempty'
+-- @
+--
+-- It got quite common to use 'Proxy' data type as an explicit way to pass
+-- types around. Above instance allows you to restrict type of result of
+-- endomorphism folding, to some extent.
+--
+-- @
+-- instance 'AnEndo' a => 'AnEndo' ('Maybe' a) where
+--     type 'EndoOperatesOn' ('Maybe' a) = 'EndoOperatesOn' a
+--
+--     'anEndo' 'Nothing'  = 'mempty' -- = Endo 'id'
+--     'anEndo' ('Just' e) = 'anEndo' e
+--
+--     -- Definition of 'aDualEndo' is analogous.
+-- @
+--
+-- Instance for @Maybe@ lets us conditionally inject endomorphism in to a
+-- folding chain.
+--
+-- @
+-- instance 'AnEndo' a => 'AnEndo' ('Identity' a) where
+--     type 'EndoOperatesOn' ('Identity' a) = 'EndoOperatesOn' a
+--
+--     'anEndo' ('Identity' e) = 'anEndo' e
+--     'aDualEndo' ('Identity' e) = 'aDualEndo' e
+-- @
+--
+-- Above instance allows us to discard 'Identity' wrapper, which is commonly
+-- used in data types that are parametrized by functor or monad.
+class AnEndo a where
+    -- | Extract type on which endomorphism operates, e.g. for
+    -- @('Endo' a)@ it would be @a@.
+    type EndoOperatesOn a
+
+    -- | Convert value encoding @(a -> a)@ in to 'Endo'. Default
+    -- implementation:
+    --
+    -- @
+    -- 'anEndo' = 'getDual' . 'aDualEndo'
+    -- @
+    anEndo :: a -> Endo (EndoOperatesOn a)
+    anEndo = getDual . aDualEndo
+
+    -- | Dual to 'anEndo'. Default implementation:
+    --
+    -- @
+    -- 'aDualEndo' = 'Dual' . 'anEndo'
+    -- @
+    aDualEndo :: a -> Dual (Endo (EndoOperatesOn a))
+    aDualEndo = Dual . anEndo
+
+#if HAVE_MINIMAL_PRAGMA
+    {-# MINIMAL anEndo | aDualEndo #-}
+#endif
+
+instance AnEndo (Endo a) where
+    type EndoOperatesOn (Endo a) = a
+    anEndo = id
+
+instance AnEndo (a -> a) where
+    type EndoOperatesOn (a -> a) = a
+    anEndo = Endo
+
+instance AnEndo a => AnEndo (Identity a) where
+    type EndoOperatesOn (Identity a) = EndoOperatesOn a
+
+    anEndo (Identity e) = anEndo e
+    aDualEndo (Identity e) = aDualEndo e
+
+instance AnEndo a => AnEndo (Maybe a) where
+    type EndoOperatesOn (Maybe a) = EndoOperatesOn a
+
+    anEndo Nothing  = mempty
+    anEndo (Just e) = anEndo e
+
+    aDualEndo Nothing  = mempty
+    aDualEndo (Just e) = aDualEndo e
+
+#ifdef HAVE_PROXY
+-- | Constructs identity endomorphism for specified phantom type.
+instance AnEndo (Proxy a) where
+    type EndoOperatesOn (Proxy a) = a
+
+    anEndo    Proxy = mempty
+    aDualEndo Proxy = mempty
+#endif
+
+#ifdef HAVE_SEMIGROUPS
+-- | Has same semantics as 'Maybe' and it is actually defined in terms of
+-- 'AnEndo' instance for 'Maybe'.
+instance AnEndo a => AnEndo (Option a) where
+    type EndoOperatesOn (Option a) = EndoOperatesOn a
+
+    anEndo (Option maybe) = anEndo maybe
+    aDualEndo (Option maybe) = aDualEndo maybe
+#endif
+
+-- {{{ Foldable Instances -----------------------------------------------------
+
+-- | Wrapper for 'Foldable' types. Used to provide instances that work for all
+-- 'Foldable' types without the need for @OverlappingInstances@ language
+-- extension.
+newtype WrappedFoldable f a = WrapFoldable {getFoldable :: f a}
+  deriving
+    ( Applicative
+    , Foldable
+    , Functor
+    , Generic
+    , Generic1
+    , Monad
+    , Read
+    , Show
+    , Traversable
+#ifdef HAVE_KIND_POLYMORPHIC_TYPEABLE
+    , Data
+    , Typeable
+#endif
+#ifdef HAVE_FUNCTOR_CLASSES
+    , Eq1
+    , Ord1
+#endif
+    )
+
+#ifdef HAVE_FUNCTOR_CLASSES
+instance Read1 f => Read1 (WrappedFoldable f) where
+    liftReadsPrec rp rl = readsData
+        $ readsUnaryWith (liftReadsPrec rp rl) "WrapFoldable" WrapFoldable
+
+instance Show1 f => Show1 (WrappedFoldable f) where
+    liftShowsPrec sp sl d (WrapFoldable x) =
+        showsUnaryWith (liftShowsPrec sp sl) "WrapFoldable" d x
+#endif
+    -- HAVE_FUNCTOR_CLASSES
+
+instance (Foldable f, AnEndo a) => AnEndo (WrappedFoldable f a) where
+    type EndoOperatesOn (WrappedFoldable f a) = EndoOperatesOn a
+    anEndo    (WrapFoldable fa) = foldMap anEndo    fa
+    aDualEndo (WrapFoldable fa) = foldMap aDualEndo fa
+
+instance AnEndo a => AnEndo [a] where
+    type EndoOperatesOn [a] = EndoOperatesOn a
+    anEndo    = anEndo    . WrapFoldable
+    aDualEndo = aDualEndo . WrapFoldable
+
+-- {{{ Transformers -----------------------------------------------------------
+
+-- | Fold in reverese order.
+instance (Foldable f, AnEndo a) => AnEndo (Reverse f a) where
+    type EndoOperatesOn (Reverse f a) = EndoOperatesOn a
+    anEndo    = anEndo    . WrapFoldable
+    aDualEndo = aDualEndo . WrapFoldable
+
+-- }}} Transformers -----------------------------------------------------------
+
+-- }}} Foldable Instances -----------------------------------------------------
+
+-- {{{ Instances For Tuples ---------------------------------------------------
+
+instance
+    ( AnEndo a
+    , AnEndo b
+    , EndoOperatesOn a ~ EndoOperatesOn b
+    ) => AnEndo (a, b)
+  where
+    type EndoOperatesOn (a, b) = EndoOperatesOn a
+    anEndo    (a, b) = anEndo    a <> anEndo    b
+    aDualEndo (a, b) = aDualEndo a <> aDualEndo b
+
+instance
+    ( AnEndo a
+    , AnEndo b
+    , AnEndo c
+    , EndoOperatesOn a ~ EndoOperatesOn b
+    , EndoOperatesOn a ~ EndoOperatesOn c
+    ) => AnEndo (a, b, c)
+  where
+    type EndoOperatesOn (a, b, c) = EndoOperatesOn a
+    anEndo    (a, b, c) = anEndo    a <> anEndo    b <> anEndo    c
+    aDualEndo (a, b, c) = aDualEndo a <> aDualEndo b <> aDualEndo c
+
+instance
+    ( AnEndo a1
+    , AnEndo a2
+    , AnEndo a3
+    , AnEndo a4
+    , EndoOperatesOn a1 ~ EndoOperatesOn a2
+    , EndoOperatesOn a1 ~ EndoOperatesOn a3
+    , EndoOperatesOn a1 ~ EndoOperatesOn a4
+    ) => AnEndo (a1, a2, a3, a4)
+  where
+    type EndoOperatesOn (a1, a2, a3, a4) = EndoOperatesOn a1
+    anEndo (a1, a2, a3, a4) = mconcat
+        [ anEndo a1
+        , anEndo a2
+        , anEndo a3
+        , anEndo a4
+        ]
+
+    aDualEndo (a1, a2, a3, a4) = mconcat
+        [ aDualEndo a1
+        , aDualEndo a2
+        , aDualEndo a3
+        , aDualEndo a4
+        ]
+
+instance
+    ( AnEndo a1
+    , AnEndo a2
+    , AnEndo a3
+    , AnEndo a4
+    , AnEndo a5
+    , EndoOperatesOn a1 ~ EndoOperatesOn a2
+    , EndoOperatesOn a1 ~ EndoOperatesOn a3
+    , EndoOperatesOn a1 ~ EndoOperatesOn a4
+    , EndoOperatesOn a1 ~ EndoOperatesOn a5
+    ) => AnEndo (a1, a2, a3, a4, a5)
+  where
+    type EndoOperatesOn (a1, a2, a3, a4, a5) = EndoOperatesOn a1
+
+    anEndo (a1, a2, a3, a4, a5) = mconcat
+        [ anEndo a1
+        , anEndo a2
+        , anEndo a3
+        , anEndo a4
+        , anEndo a5
+        ]
+
+    aDualEndo (a1, a2, a3, a4, a5) = mconcat
+        [ aDualEndo a1
+        , aDualEndo a2
+        , aDualEndo a3
+        , aDualEndo a4
+        , aDualEndo a5
+        ]
+
+instance
+    ( AnEndo a1
+    , AnEndo a2
+    , AnEndo a3
+    , AnEndo a4
+    , AnEndo a5
+    , AnEndo a6
+    , EndoOperatesOn a1 ~ EndoOperatesOn a2
+    , EndoOperatesOn a1 ~ EndoOperatesOn a3
+    , EndoOperatesOn a1 ~ EndoOperatesOn a4
+    , EndoOperatesOn a1 ~ EndoOperatesOn a5
+    , EndoOperatesOn a1 ~ EndoOperatesOn a6
+    ) => AnEndo (a1, a2, a3, a4, a5, a6)
+  where
+    type EndoOperatesOn (a1, a2, a3, a4, a5, a6) = EndoOperatesOn a1
+
+    anEndo (a1, a2, a3, a4, a5, a6) = mconcat
+        [ anEndo a1
+        , anEndo a2
+        , anEndo a3
+        , anEndo a4
+        , anEndo a5
+        , anEndo a6
+        ]
+
+    aDualEndo (a1, a2, a3, a4, a5, a6) = mconcat
+        [ aDualEndo a1
+        , aDualEndo a2
+        , aDualEndo a3
+        , aDualEndo a4
+        , aDualEndo a5
+        , aDualEndo a6
+        ]
+
+instance
+    ( AnEndo a1
+    , AnEndo a2
+    , AnEndo a3
+    , AnEndo a4
+    , AnEndo a5
+    , AnEndo a6
+    , AnEndo a7
+    , EndoOperatesOn a1 ~ EndoOperatesOn a2
+    , EndoOperatesOn a1 ~ EndoOperatesOn a3
+    , EndoOperatesOn a1 ~ EndoOperatesOn a4
+    , EndoOperatesOn a1 ~ EndoOperatesOn a5
+    , EndoOperatesOn a1 ~ EndoOperatesOn a6
+    , EndoOperatesOn a1 ~ EndoOperatesOn a7
+    ) => AnEndo (a1, a2, a3, a4, a5, a6, a7)
+  where
+    type EndoOperatesOn (a1, a2, a3, a4, a5, a6, a7) = EndoOperatesOn a1
+
+    anEndo (a1, a2, a3, a4, a5, a6, a7) = mconcat
+        [ anEndo a1
+        , anEndo a2
+        , anEndo a3
+        , anEndo a4
+        , anEndo a5
+        , anEndo a6
+        , anEndo a7
+        ]
+
+    aDualEndo (a1, a2, a3, a4, a5, a6, a7) = mconcat
+        [ aDualEndo a1
+        , aDualEndo a2
+        , aDualEndo a3
+        , aDualEndo a4
+        , aDualEndo a5
+        , aDualEndo a6
+        , aDualEndo a7
+        ]
+
+instance
+    ( AnEndo a1
+    , AnEndo a2
+    , AnEndo a3
+    , AnEndo a4
+    , AnEndo a5
+    , AnEndo a6
+    , AnEndo a7
+    , AnEndo a8
+    , EndoOperatesOn a1 ~ EndoOperatesOn a2
+    , EndoOperatesOn a1 ~ EndoOperatesOn a3
+    , EndoOperatesOn a1 ~ EndoOperatesOn a4
+    , EndoOperatesOn a1 ~ EndoOperatesOn a5
+    , EndoOperatesOn a1 ~ EndoOperatesOn a6
+    , EndoOperatesOn a1 ~ EndoOperatesOn a7
+    , EndoOperatesOn a1 ~ EndoOperatesOn a8
+    ) => AnEndo (a1, a2, a3, a4, a5, a6, a7, a8)
+  where
+    type EndoOperatesOn (a1, a2, a3, a4, a5, a6, a7, a8) = EndoOperatesOn a1
+
+    anEndo (a1, a2, a3, a4, a5, a6, a7, a8) = mconcat
+        [ anEndo a1
+        , anEndo a2
+        , anEndo a3
+        , anEndo a4
+        , anEndo a5
+        , anEndo a6
+        , anEndo a7
+        , anEndo a8
+        ]
+
+    aDualEndo (a1, a2, a3, a4, a5, a6, a7, a8) = mconcat
+        [ aDualEndo a1
+        , aDualEndo a2
+        , aDualEndo a3
+        , aDualEndo a4
+        , aDualEndo a5
+        , aDualEndo a6
+        , aDualEndo a7
+        , aDualEndo a8
+        ]
+
+instance
+    ( AnEndo a1
+    , AnEndo a2
+    , AnEndo a3
+    , AnEndo a4
+    , AnEndo a5
+    , AnEndo a6
+    , AnEndo a7
+    , AnEndo a8
+    , AnEndo a9
+    , EndoOperatesOn a1 ~ EndoOperatesOn a2
+    , EndoOperatesOn a1 ~ EndoOperatesOn a3
+    , EndoOperatesOn a1 ~ EndoOperatesOn a4
+    , EndoOperatesOn a1 ~ EndoOperatesOn a5
+    , EndoOperatesOn a1 ~ EndoOperatesOn a6
+    , EndoOperatesOn a1 ~ EndoOperatesOn a7
+    , EndoOperatesOn a1 ~ EndoOperatesOn a8
+    , EndoOperatesOn a1 ~ EndoOperatesOn a9
+    ) => AnEndo (a1, a2, a3, a4, a5, a6, a7, a8, a9)
+  where
+    type EndoOperatesOn (a1, a2, a3, a4, a5, a6, a7, a8, a9) = EndoOperatesOn a1
+
+    anEndo (a1, a2, a3, a4, a5, a6, a7, a8, a9) = mconcat
+        [ anEndo a1
+        , anEndo a2
+        , anEndo a3
+        , anEndo a4
+        , anEndo a5
+        , anEndo a6
+        , anEndo a7
+        , anEndo a8
+        , anEndo a9
+        ]
+
+    aDualEndo (a1, a2, a3, a4, a5, a6, a7, a8, a9) = mconcat
+        [ aDualEndo a1
+        , aDualEndo a2
+        , aDualEndo a3
+        , aDualEndo a4
+        , aDualEndo a5
+        , aDualEndo a6
+        , aDualEndo a7
+        , aDualEndo a8
+        , aDualEndo a9
+        ]
+
+instance
+    ( AnEndo a1
+    , AnEndo a2
+    , AnEndo a3
+    , AnEndo a4
+    , AnEndo a5
+    , AnEndo a6
+    , AnEndo a7
+    , AnEndo a8
+    , AnEndo a9
+    , AnEndo a10
+    , EndoOperatesOn a1 ~ EndoOperatesOn a2
+    , EndoOperatesOn a1 ~ EndoOperatesOn a3
+    , EndoOperatesOn a1 ~ EndoOperatesOn a4
+    , EndoOperatesOn a1 ~ EndoOperatesOn a5
+    , EndoOperatesOn a1 ~ EndoOperatesOn a6
+    , EndoOperatesOn a1 ~ EndoOperatesOn a7
+    , EndoOperatesOn a1 ~ EndoOperatesOn a8
+    , EndoOperatesOn a1 ~ EndoOperatesOn a9
+    , EndoOperatesOn a1 ~ EndoOperatesOn a10
+    ) => AnEndo (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
+  where
+    type EndoOperatesOn (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) = EndoOperatesOn a1
+
+    anEndo (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) = mconcat
+        [ anEndo a1
+        , anEndo a2
+        , anEndo a3
+        , anEndo a4
+        , anEndo a5
+        , anEndo a6
+        , anEndo a7
+        , anEndo a8
+        , anEndo a9
+        , anEndo a10
+        ]
+
+    aDualEndo (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) = mconcat
+        [ aDualEndo a1
+        , aDualEndo a2
+        , aDualEndo a3
+        , aDualEndo a4
+        , aDualEndo a5
+        , aDualEndo a6
+        , aDualEndo a7
+        , aDualEndo a8
+        , aDualEndo a9
+        , aDualEndo a10
+        ]
+
+-- }}} Instances For Tuples ---------------------------------------------------
+-- }}} AnEndo Type Class ------------------------------------------------------
+
+-- {{{ Utility Functions and Types --------------------------------------------
+
+-- | Use 'Endo' (possibly result of 'Data.Endo.Fold.foldEndo') and use it to
+-- create value of different type.
+--
+-- Examples:
+--
+-- @
+-- 'embedEndoWith' 'Control.Monad.Trans.Writer.Lazy.tell'
+--     :: (Monad m, 'AnEndo' e, w ~ 'EndoOperatesOn' e)
+--     => e
+--     -> 'Control.Monad.Trans.Writer.Lazy.WriterT' ('Endo' w) m ()
+--
+-- 'embedEndoWith' ('Control.Monad.Trans.State.Lazy.modify' . 'Data.Monoid.appEndo')
+--     :: (Monad m, 'AnEndo' e, s ~ 'EndoOperatesOn' e)
+--     => e
+--     -> 'Control.Monad.Trans.State.Lazy.StateT' s m ()
+-- @
+--
+-- See also 'embedDualEndoWith'.
+embedEndoWith :: (AnEndo e, EndoOperatesOn e ~ a)
+    => (Endo a -> b)
+    -- ^ Embedding function.
+    -> e -> b
+embedEndoWith = (. anEndo)
+
+-- | Dual to 'embedEndoWith', which uses 'aDualEndo' instead of 'anEndo'.
+embedDualEndoWith
+    :: (AnEndo e, EndoOperatesOn e ~ a)
+    => (Dual (Endo a) -> b)
+    -- ^ Embedding function.
+    -> e -> b
+embedDualEndoWith = (. aDualEndo)
+
+-- }}} Utility Functions and Types --------------------------------------------
+
+-- $wrappedFoldable
+--
+-- Newtype 'WrappedFoldable' allows us to use 'anEndo', 'aDualEndo',
+-- 'Data.Endo.Fold.foldEndo', and 'Data.Endo.Fold.dualFoldEndo' for any
+-- 'Foldable' instance without the need to create specific instance for that
+-- specific 'Foldable' type and reduces. It would be possible to create
+-- 'AnEndo' instance for all 'Foldable' types, but that would require
+-- @OverlappingInstances@ language extension.
+--
+-- Usage examples:
+--
+-- @
+-- \\vectorOfEndos -> 'anEndo' ('WrappedFoldable' vectorOfEndos)
+--     :: Vector ('Data.Monoid.Endo.E' a) -> 'Endo' a
+-- @
+--
+-- @
+-- \\vectorOfEndos -> 'Data.Monoid.Endo.Fold.foldEndo' ('WrappedFoldable' vectorOfEndos)
+--     :: 'Data.Monoid.Endo.Fold.FoldEndoArgs' => Vector ('Data.Monoid.Endo.E' a) -> args
+-- @
+--
+-- Note that the @Vector@ is just one of possible 'Foldable' data types that
+-- may be used here. Also, @('Data.Monoid.Endo.E' a)@ is just an example of
+-- endomorphism representation, any 'AnEndo' instance can be used.
diff --git a/src/Data/Monoid/Endo/Apply.hs b/src/Data/Monoid/Endo/Apply.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Monoid/Endo/Apply.hs
@@ -0,0 +1,425 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE DeriveTraversable #-}  -- GeneralizedNewtypeDeriving failed.
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE TypeFamilies #-}
+
+#ifdef HAVE_KIND_POLYMORPHIC_TYPEABLE
+{-# LANGUAGE DeriveDataTypeable #-}
+#endif
+
+#if MIN_VERSION_transformers(0,5,0) || MIN_VERSION_base(4,9,0)
+#define HAVE_FUNCTOR_CLASSES
+#endif
+
+-- |
+-- Module:       $HEADER$
+-- Description:  ApplyEndo provides easier endomorphism evaluation in cases
+--               when there is an "obvious" default value.
+-- Copyright:    (c) 2015-2016, Peter Trško
+-- License:      BSD3
+--
+-- Maintainer:   peter.trsko@gmail.com
+-- Stability:    experimental
+-- Portability:  CPP, DeriveFoldable, DeriveFunctor, DeriveDataTypeable,
+--               DeriveGeneric, DeriveTraversable, FlexibleInstances,
+--               NoImplicitPrelude, TypeFamilies
+--
+-- 'ApplyEndo' provides easier endomorphism evaluation in cases when there is an
+-- \"obvious\" default value.
+module Data.Monoid.Endo.Apply
+    (
+    -- * ApplyEndo
+      ApplyEndo(..)
+    , apply
+    , applyF
+
+    -- ** ApplyEndo Mempty
+    , Mempty
+    , applyMempty
+    , applyMempty_
+    , joinApplyMempty
+
+    -- ** ApplyEndo Def
+    --
+    -- $applyEndoDef
+    , Def
+    , applyDef
+    , applyDef_
+    , joinApplyDef
+
+    -- ** ApplyEndo Reader
+    , Reader
+    , applyReader
+    , applyReaderWith
+    , joinApplyReader
+
+    -- ** ApplyEndo Modify
+    , Modify
+    , applyModify
+    , joinApplyModify
+
+    -- ** ApplyEndo Modify'
+    , Modify'
+    , applyModify'
+    , joinApplyModify'
+
+    )
+  where
+
+import Prelude (seq)
+
+import Control.Applicative (Applicative(pure))
+import Control.Monad
+    ( Monad((>>=))
+#ifdef HAVE_APPLICATIVE_MONAD
+    , void
+#else
+    , liftM
+#endif
+    )
+import Data.Foldable (Foldable)
+import Data.Function
+    ( (.)
+    , ($)
+#ifndef HAVE_APPLICATIVE_MONAD
+    , const
+#endif
+    )
+import Data.Functor (Functor, (<$>))
+#ifdef HAVE_FUNCTOR_CLASSES
+import Data.Functor.Classes
+    ( Eq1
+    , Ord1
+    , Read1(liftReadsPrec)
+    , Show1(liftShowsPrec)
+    , readsData
+    , readsUnaryWith
+    , showsUnaryWith
+    )
+#endif
+import Data.Functor.Identity (Identity(runIdentity))
+import Data.Monoid (Endo(Endo, appEndo), Monoid(mempty))
+import Data.Traversable (Traversable)
+import GHC.Generics (Generic, Generic1)
+
+#ifdef HAVE_KIND_POLYMORPHIC_TYPEABLE
+import Data.Data (Data, Typeable)
+#endif
+
+import Control.Monad.Reader.Class (MonadReader)
+import qualified Control.Monad.Reader.Class as MonadReader (asks)
+import Control.Monad.State.Class (MonadState)
+import qualified Control.Monad.State.Class as MonadState (state)
+
+import Data.Default.Class (Default(def))
+
+import Data.Monoid.Endo.FromEndo (FromEndo(..))
+
+
+-- | There are cases when it is \"obvious\" what is the default value, which
+-- should be modified by the endomorphism. This type is a result of such
+-- endomorphism application and it uses phantom type @t@ as distinguishing
+-- property, which decides what is the correct \"default value\".
+newtype ApplyEndo t f a = ApplyEndo {applyEndo :: f a}
+  deriving
+    ( Applicative
+    , Foldable
+    , Functor
+    , Generic
+    , Generic1
+    , Monad
+    , Traversable
+#ifdef HAVE_KIND_POLYMORPHIC_TYPEABLE
+    , Data
+    , Typeable
+#endif
+#ifdef HAVE_FUNCTOR_CLASSES
+    , Eq1
+    , Ord1
+#endif
+    )
+
+#ifdef HAVE_FUNCTOR_CLASSES
+instance Read1 f => Read1 (ApplyEndo t f) where
+    liftReadsPrec rp rl =
+        readsData $ readsUnaryWith (liftReadsPrec rp rl) "ApplyEndo" ApplyEndo
+
+instance Show1 f => Show1 (ApplyEndo t f) where
+    liftShowsPrec sp sl d (ApplyEndo x) =
+        showsUnaryWith (liftShowsPrec sp sl) "ApplyEndo" d x
+#endif
+    -- HAVE_FUNCTOR_CLASSES
+
+-- | Apply endomorphism using provided \"default\" value.
+apply :: Applicative f => a -> Endo a -> ApplyEndo t f a
+apply defaultValue (Endo f) = ApplyEndo . pure $ f defaultValue
+{-# INLINE apply #-}
+
+-- | Similar as 'apply', but expects 'Endo' to be wrapped by a 'Functor'.
+applyF :: Functor f => a -> f (Endo a) -> ApplyEndo t f a
+applyF defaultValue endo = ApplyEndo $ (`appEndo` defaultValue) <$> endo
+
+-- {{{ ApplyEndo Mempty -------------------------------------------------------
+
+-- | Type tag identifying usage of 'mempty' from 'Monoid'.
+data Mempty
+  deriving
+    ( Generic
+#ifdef HAVE_KIND_POLYMORPHIC_TYPEABLE
+    , Typeable
+#endif
+    )
+
+instance (Applicative f, Monoid a) => FromEndo (ApplyEndo Mempty f a) where
+    type EndoOperatedOn (ApplyEndo Mempty f a) = a
+
+    fromEndo = apply mempty
+
+-- | Constrained version of 'applyEndo'. Usage example:
+--
+-- @
+-- applyMempty . fromEndo :: ('Applicative' f, 'Monoid' a) => 'Endo' a -> f a
+-- @
+applyMempty :: Monoid a => ApplyEndo Mempty f a -> f a
+applyMempty = applyEndo
+{-# INLINE applyMempty #-}
+
+-- | Same as 'applyMempty', but 'Applicative' functor is specialized to
+-- 'Identity' functor and evaluated.
+--
+-- Examples:
+--
+-- >>> fromEndoWith applyMempty_ $ foldEndo (+1) [(*10), (+42)] :: Int
+-- 421
+-- >>> fromEndoWith applyMempty_ $ dualFoldEndo (+1) [(*10), (+42)] :: Int
+-- 52
+applyMempty_ :: Monoid a => ApplyEndo Mempty Identity a -> a
+applyMempty_ = runIdentity . applyMempty
+{-# INLINE applyMempty_ #-}
+
+-- | Evaluates 'ApplyEndo' in a 'Monad' by joining it with the monad it
+-- contains. It can be also viewed as a variant of 'applyMempty' defined as:
+--
+-- @
+-- 'joinApplyMempty' = ('>>=' 'applyMempty')
+-- @
+joinApplyMempty
+    ::  ( Monad m
+        , Monoid a
+#ifndef HAVE_APPLICATIVE_MONAD
+        , Applicative m
+#endif
+        )
+    => m (ApplyEndo Mempty m a) -> m a
+joinApplyMempty = (>>= applyMempty)
+{-# INLINE joinApplyMempty #-}
+
+-- }}} ApplyEndo Mempty -------------------------------------------------------
+
+-- {{{ ApplyEndo Def ----------------------------------------------------------
+
+-- $applyEndoDef
+--
+-- Apply endomorphism to a default value 'def' from 'Default'. See also
+-- following packages:
+--
+-- * <https://hackage.haskell.org/package/data-default-extra data-default-extra>
+--
+-- * <https://hackage.haskell.org/package/data-default data-default>
+--
+-- Both of those packages provide additional instances to 'Default' type
+-- class.
+
+-- | Type tag identifying usage of 'def' from 'Default'.
+data Def
+  deriving
+    ( Generic
+#ifdef HAVE_KIND_POLYMORPHIC_TYPEABLE
+    , Typeable
+#endif
+    )
+
+instance (Applicative f, Default a) => FromEndo (ApplyEndo Def f a) where
+    type EndoOperatedOn (ApplyEndo Def f a) = a
+
+    fromEndo = apply def
+
+-- | Constrained version of 'applyEndo'. Usage example:
+--
+-- @
+-- applyDef . fromEndo :: ('Applicative' f, 'Default' a) => 'Endo' a -> f a
+-- @
+applyDef :: (Applicative f, Default a) => ApplyEndo Def f a -> f a
+applyDef = applyEndo
+{-# INLINE applyDef #-}
+
+-- | Same as 'applyDef', but 'Applicative' functor is specialized to 'Identity'
+-- functor and evaluated.
+--
+-- Examples:
+--
+-- >>> fromEndoWith applyDef_ $ foldEndo (+1) [(*10), (+42)] :: Int
+-- 421
+-- >>> fromEndoWith applyDef_ $ dualFoldEndo (+1) [(*10), (+42)] :: Int
+-- 52
+applyDef_ :: Default a => ApplyEndo Def Identity a -> a
+applyDef_ = runIdentity . applyDef
+{-# INLINE applyDef_ #-}
+
+-- | Evaluates 'ApplyEndo' in a 'Monad' by joining it with the monad it
+-- contains. It can be also viewed as a variant of 'applyDef' defined as:
+--
+-- @
+-- 'joinApplyDef' = ('>>=' 'applyDef')
+-- @
+joinApplyDef
+    ::  ( Monad m
+        , Default a
+#ifndef HAVE_APPLICATIVE_MONAD
+        , Applicative m
+#endif
+        )
+    => m (ApplyEndo Def m a) -> m a
+joinApplyDef = (>>= applyDef)
+{-# INLINE joinApplyDef #-}
+
+-- }}} ApplyEndo Def ----------------------------------------------------------
+
+-- {{{ ApplyEndo Reader -------------------------------------------------------
+
+-- | Type tag identifying usage of 'MonadReader.asks' operation in 'FromEndo'
+-- instance of 'ApplyEndo'.
+data Reader
+  deriving
+    ( Generic
+#ifdef HAVE_KIND_POLYMORPHIC_TYPEABLE
+    , Typeable
+#endif
+    )
+
+-- | Evaluates 'ApplyEndo' in terms of 'MonadReader.asks' operation:
+--
+-- @
+-- 'fromEndo' = 'ApplyEndo' . 'MonadReader.asks' . 'appEndo'
+-- @
+instance MonadReader r m => FromEndo (ApplyEndo Reader m r) where
+    type EndoOperatedOn (ApplyEndo Reader m r) = r
+
+    fromEndo = ApplyEndo . MonadReader.asks . appEndo
+
+-- | Evaluates 'ApplyEndo' in terms of 'MonadReader.asks' operation.
+--
+-- This @(->) r@ is a valid 'MonadReader' instance, therefore, this is a valid
+-- use case:
+--
+-- >>> (applyReader . fromEndo $ foldEndo (*10) (+1)) 0 :: Int
+-- 10
+applyReader :: MonadReader r m => ApplyEndo Reader m r -> m r
+applyReader = applyEndo
+
+-- | Evaluates 'ApplyEndo' in terms of 'MonadReader.asks' operation and then
+-- evaluates the resalt using provided function.
+--
+-- This @(->) r@ is a valid 'MonadReader' instance, therefore, this is a valid
+-- use case:
+--
+-- >>> applyReaderWith ($ 0) . fromEndo $ foldEndo (*10) (+1) :: Int
+-- 10
+applyReaderWith :: MonadReader r m => (m r -> a) -> ApplyEndo Reader m r -> a
+applyReaderWith = (. applyEndo)
+
+-- | Evaluates 'ApplyEndo' in a 'Monad' by joining it with the monad it
+-- contains. It can be also viewed as a variant of 'applyReader' defined as:
+--
+-- @
+-- 'joinApplyReader' = ('>>=' 'applyReader')
+-- @
+joinApplyReader :: MonadReader r m => m (ApplyEndo Reader m r) -> m r
+joinApplyReader = (>>= applyEndo)
+
+-- }}} ApplyEndo Reader -------------------------------------------------------
+
+-- {{{ ApplyEndo Modify -------------------------------------------------------
+
+-- | Type tag identifying usage of 'MonadState.state' operation in 'FromEndo'
+-- instance of 'ApplyEndo'.
+data Modify
+  deriving
+    ( Generic
+#ifdef HAVE_KIND_POLYMORPHIC_TYPEABLE
+    , Typeable
+#endif
+    )
+
+-- | Evaluates 'ApplyEndo' in terms of 'MonadState.state' operation:
+--
+-- @
+-- 'fromEndo' e = 'ApplyEndo' . 'MonadState.state' '$' \\s ->
+--     let s' = 'appEndo' e s in (s', s')
+-- @
+instance MonadState s m => FromEndo (ApplyEndo Modify m s) where
+    type EndoOperatedOn (ApplyEndo Modify m s) = s
+
+    fromEndo e =
+        ApplyEndo . MonadState.state $ \s -> let s' = appEndo e s in (s', s')
+
+-- | Evaluates 'ApplyEndo' in terms of 'MonadState.state' operation.
+applyModify :: MonadState s m => ApplyEndo Modify m s -> m s
+applyModify = applyEndo
+
+-- | Evaluates 'ApplyEndo' in a 'Monad' by joining it with the monad it
+-- contains. It can be also viewed as a variant of 'applyModify' defined as:
+--
+-- @
+-- 'joinApplyModify' = ('>>=' 'applyModify')
+-- @
+joinApplyModify :: MonadState s m => m (ApplyEndo Modify m s) -> m s
+joinApplyModify = (>>= applyEndo)
+
+-- | Same as 'Modify', but strictness is implied.
+data Modify'
+  deriving
+    ( Generic
+#ifdef HAVE_KIND_POLYMORPHIC_TYPEABLE
+    , Typeable
+#endif
+    )
+
+-- | Evaluates 'ApplyEndo' in terms of 'MonadState.state' operation:
+--
+-- @
+-- 'fromEndo' ('Endo' f) = 'ApplyEndo' . 'MonadState.state' $ \\s ->
+--     let s' = f s in s' \`seq\` (s', s')
+-- @
+instance MonadState s m => FromEndo (ApplyEndo Modify' m s) where
+    type EndoOperatedOn (ApplyEndo Modify' m s) = s
+
+    fromEndo (Endo f) =
+        ApplyEndo . MonadState.state $ \s -> let s' = f s in s' `seq` (s', s')
+
+-- | Evaluates 'ApplyEndo' in terms of 'MonadState.state' operation.
+applyModify' :: MonadState r m => ApplyEndo Modify' m () -> m ()
+applyModify' = void . applyEndo
+
+-- | Evaluates 'ApplyEndo' in a 'Monad' by joining it with the monad it
+-- contains. It can be also viewed as a variant of 'applyModify'' defined as:
+--
+-- @
+-- 'joinApplyModify'' = ('>>=' 'applyModify'')
+-- @
+joinApplyModify' :: MonadState r m => m (ApplyEndo Modify' m r) -> m r
+joinApplyModify' = (>>= applyEndo)
+
+-- }}} ApplyEndo Modify -------------------------------------------------------
+
+-- {{{ Helper functions (not exported) ----------------------------------------
+
+#ifndef HAVE_APPLICATIVE_MONAD
+void :: Monad m => m a -> m ()
+void = liftM $ const ()
+#endif
+
+-- {{{ Helper functions (not exported) ----------------------------------------
diff --git a/src/Data/Monoid/Endo/Fold.hs b/src/Data/Monoid/Endo/Fold.hs
--- a/src/Data/Monoid/Endo/Fold.hs
+++ b/src/Data/Monoid/Endo/Fold.hs
@@ -1,12 +1,9 @@
 {-# LANGUAGE CPP #-}
-{-# LANGUAGE DeriveGeneric #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE TypeFamilies #-}
-
-#ifdef KIND_POLYMORPHIC_TYPEABLE
-{-# LANGUAGE DeriveDataTypeable #-}
-#endif
+{-# LANGUAGE TypeOperators #-}
 
 #if MIN_VERSION_transformers(0,4,0)
 -- ExceptT was introduced in transformers == 0.4.0.0 and it deprecated ErrorT.
@@ -14,22 +11,16 @@
 #define HAVE_EXCEPTT
 #endif
 
-#if MIN_VERSION_base(4,7,0)
--- Module Data.Proxy, that defines Proxy data type, was introduced in
--- base == 4.7.0.0.
-#define HAVE_PROXY
-#endif
-
 -- |
 -- Module:       $HEADER$
 -- Description:  Generic folding for various endomorphism representations.
--- Copyright:    (c) 2014-2015, Peter Trško
+-- Copyright:    (c) 2014-2016, Peter Trško
 -- License:      BSD3
 --
 -- Maintainer:   peter.trsko@gmail.com
 -- Stability:    experimental
 -- Portability:  CPP, DeriveDataTypeable, DeriveGeneric, FlexibleInstances,
---               NoImplicitPrelude, TypeFamilies
+--               NoImplicitPrelude, RankNTypes, TypeOperators, TypeFamilies
 --
 -- Generic folding for various endomorphism representations.
 module Data.Monoid.Endo.Fold
@@ -65,7 +56,8 @@
     -- ** Type Wrappers
     , WrappedFoldable(..)
 
-    -- * Utility Functions
+    -- * Utility Functions and Types
+    , (:->)
     , (&$)
     , (<&$>)
     , embedEndoWith
@@ -73,29 +65,24 @@
     )
   where
 
-import Control.Applicative (Applicative(pure), Const(Const))
+import Control.Applicative
+    ( Applicative(pure)
+#ifndef HAVE_FUNCTOR_CONST_MODULE
+    , Const(Const)
+#endif
+    )
 import Control.Monad (Monad(return))
 import Data.Either (Either(Right))
-import Data.Foldable (Foldable(foldMap))
 import Data.Function ((.), id)
 import Data.Functor (Functor(fmap))
+#ifdef HAVE_FUNCTOR_CONST_MODULE
+import Data.Functor.Const (Const(Const))
+#endif
 import Data.Functor.Identity (Identity(Identity))
-import Data.Maybe (Maybe(Just, Nothing))
-import Data.Monoid (Dual(Dual, getDual), Endo(Endo), Monoid(mempty, mconcat), (<>))
-import GHC.Generics (Generic)
+import Data.Maybe (Maybe(Just))
+import Data.Monoid (Dual(Dual), Endo, Monoid(mempty), (<>))
 import System.IO (IO)
-import Text.Read (Read)
-import Text.Show (Show)
 
-#ifdef KIND_POLYMORPHIC_TYPEABLE
-import Data.Data (Data)
-import Data.Typeable (Typeable)
-#endif
-
-#ifdef HAVE_PROXY
-import Data.Proxy (Proxy(Proxy))
-#endif
-
 #ifdef HAVE_EXCEPTT
 import Control.Monad.Trans.Except (ExceptT)
 #endif
@@ -111,9 +98,15 @@
 import qualified Control.Monad.Trans.Writer.Strict as Strict (WriterT)
 import Data.Functor.Compose (Compose)
 import Data.Functor.Product (Product)
-import Data.Functor.Reverse (Reverse)
 
+import Data.Monoid.Endo.AnEndo
+    ( AnEndo(..)
+    , WrappedFoldable(..)
+    , embedDualEndoWith
+    , embedEndoWith
+    )
 
+
 -- | Fold all variously represented endomorphisms in to one endomorphism.
 --
 -- Order in which endomorphisms are folded is preserved:
@@ -141,7 +134,7 @@
 -- Order in which endomorphisms are folded is reversed:
 --
 -- >>> dualFoldEndo (Endo (1:)) [(2:), (3:)] `appEndo` []
--- [2,3,1]
+-- [3,2,1]
 --
 -- For numbers it would look like:
 --
@@ -230,8 +223,8 @@
 -- Examples:
 --
 -- @
--- 'foldEndo' \<*\> ((++) \<$\> getLine) \<*\> ((++) \<$\> getLine)
---     :: :: ('FoldEndoArgs' r, 'ResultOperatesOn' r ~ String) => IO r
+-- 'foldEndo' \<*\> ((<>) \<$\> getLine) \<*\> ((<>) \<$\> getLine)
+--     :: ('FoldEndoArgs' r, 'ResultOperatesOn' r ~ String) => IO r
 -- @
 --
 -- In the next example, prefix @ghci\>@ indicates GHCi prompt, @ghci|@ is GHCi
@@ -304,7 +297,7 @@
 #ifdef HAVE_EXCEPTT
 instance
     ( Monad m
-#ifndef APPLICATIVE_MONAD
+#ifndef HAVE_APPLICATIVE_MONAD
     , Functor m
 #endif
     , FoldEndoArgs r
@@ -324,7 +317,7 @@
 
 instance
     ( Monad m
-#ifndef APPLICATIVE_MONAD
+#ifndef HAVE_APPLICATIVE_MONAD
     , Functor m
 #endif
     , FoldEndoArgs r
@@ -342,7 +335,7 @@
 
 instance
     ( Monad m
-#ifndef APPLICATIVE_MONAD
+#ifndef HAVE_APPLICATIVE_MONAD
     , Functor m
 #endif
     , Monoid w
@@ -356,7 +349,7 @@
 
 instance
     ( Monad m
-#ifndef APPLICATIVE_MONAD
+#ifndef HAVE_APPLICATIVE_MONAD
     , Functor m
 #endif
     , Monoid w
@@ -401,422 +394,29 @@
 
 -- }}} Transformers -----------------------------------------------------------
 
--- {{{ FoldEndoArgs Type Class ------------------------------------------------
+-- }}} FoldEndoArgs Type Class ------------------------------------------------
 
--- {{{ AnEndo Type Class ------------------------------------------------------
+-- {{{ Utility Functions and Types --------------------------------------------
 
--- | Class that represents various endomorphism representation. In other words
--- anything that encodes @a -> a@ can be instance of this class.
---
--- Here are some important instances with not so obvious definitions.
+-- | Type alias that restricts type of endomorphism folding result, and it
+-- looks similar to @->@. Example of creating version of 'foldEndo' with
+-- specific result:
 --
 -- @
--- instance 'AnEndo' ('Proxy' a) where
---     type 'EndoOperatesOn' ('Proxy' a) = a
---
---     'anEndo'    _ = 'mempty' -- = Endo 'id'
---     'aDualEndo' _ = 'mempty'
+-- foldToEndoString :: 'FoldEndoArgs' args => args ':->' 'Endo' String
+-- foldToEndoString = 'foldEndo'
 -- @
 --
--- It got quite common to use 'Proxy' data type as an explicit way to pass
--- types around. Above instance allows you to restrict type of result of
--- endomorphism folding, to some extent.
---
--- @
--- instance 'AnEndo' a => 'AnEndo' (Maybe a) where
---     type 'EndoOperatesOn' (Maybe a) = 'EndoOperatesOn' a
+-- >>> foldToEndoString ("foo" <>) ("bar" <>) `appEndo` "baz"
+-- "foobarbaz"
 --
---     'anEndo' Nothing  = 'mempty' -- = Endo 'id'
---     'anEndo' (Just e) = 'anEndo' e
+-- Following type signatures for 'foldEndoArgs' are equivalent:
 --
---     -- Definition of 'aDualEndo' is analogous.
 -- @
---
--- Instance for @Maybe@ lets us conditionally inject endomorphism in to a
--- folding chain.
-class AnEndo a where
-    -- | Extract type on which endomorphism operates, e.g. for
-    -- @'Endo' a@ it would be @a@.
-    type EndoOperatesOn a
-
-    -- | Convert value encoding @a -> a@ in to 'Endo'. Default implementation:
-    --
-    -- @
-    -- 'anEndo' = 'getDual' . 'aDualEndo'
-    -- @
-    anEndo :: a -> Endo (EndoOperatesOn a)
-    anEndo = getDual . aDualEndo
-
-    -- | Dual to 'anEndo'. Default implementation:
-    --
-    -- @
-    -- 'aDualEndo' = 'Dual' . 'anEndo'
-    -- @
-    aDualEndo :: a -> Dual (Endo (EndoOperatesOn a))
-    aDualEndo = Dual . anEndo
-
-#if HAVE_MINIMAL_PRAGMA
-    {-# MINIMAL anEndo | aDualEndo #-}
-#endif
-
-instance AnEndo (Endo a) where
-    type EndoOperatesOn (Endo a) = a
-    anEndo = id
-
-instance AnEndo (a -> a) where
-    type EndoOperatesOn (a -> a) = a
-    anEndo = Endo
-
-instance AnEndo a => AnEndo (Maybe a) where
-    type EndoOperatesOn (Maybe a) = EndoOperatesOn a
-
-    anEndo Nothing  = mempty
-    anEndo (Just e) = anEndo e
-
-    aDualEndo Nothing  = mempty
-    aDualEndo (Just e) = aDualEndo e
-
-#ifdef HAVE_PROXY
--- | Constructs identity endomorphism for specified phantom type.
-instance AnEndo (Proxy a) where
-    type EndoOperatesOn (Proxy a) = a
-
-    anEndo    Proxy = mempty
-    aDualEndo Proxy = mempty
-#endif
-
--- {{{ Foldable Instances -----------------------------------------------------
-
--- | Wrapper for 'Foldable' instances.
---
--- This allows using 'foldEndo' and 'dualFoldEndo' for any 'Foldable' instance
--- without the need for @OverlappingInstances@ language extension.
-newtype WrappedFoldable f a = WrapFoldable {getFoldable :: f a}
-  deriving
-    ( Generic
-    , Read
-    , Show
-#ifdef KIND_POLYMORPHIC_TYPEABLE
-    , Data
-    , Typeable
-#endif
-    )
-
-instance (Foldable f, AnEndo a) => AnEndo (WrappedFoldable f a) where
-    type EndoOperatesOn (WrappedFoldable f a) = EndoOperatesOn a
-    anEndo    (WrapFoldable fa) = foldMap anEndo    fa
-    aDualEndo (WrapFoldable fa) = foldMap aDualEndo fa
-
-instance AnEndo a => AnEndo [a] where
-    type EndoOperatesOn [a] = EndoOperatesOn a
-    anEndo    = anEndo    . WrapFoldable
-    aDualEndo = aDualEndo . WrapFoldable
-
--- {{{ Transformers -----------------------------------------------------------
-
--- | Fold in reverese order.
-instance (Foldable f, AnEndo a) => AnEndo (Reverse f a) where
-    type EndoOperatesOn (Reverse f a) = EndoOperatesOn a
-    anEndo    = anEndo    . WrapFoldable
-    aDualEndo = aDualEndo . WrapFoldable
-
--- }}} Transformers -----------------------------------------------------------
-
--- }}} Foldable Instances -----------------------------------------------------
-
--- {{{ Instances For Tuples ---------------------------------------------------
-
-instance
-    ( AnEndo a
-    , AnEndo b
-    , EndoOperatesOn a ~ EndoOperatesOn b
-    ) => AnEndo (a, b)
-  where
-    type EndoOperatesOn (a, b) = EndoOperatesOn a
-    anEndo    (a, b) = anEndo    a <> anEndo    b
-    aDualEndo (a, b) = aDualEndo a <> aDualEndo b
-
-instance
-    ( AnEndo a
-    , AnEndo b
-    , AnEndo c
-    , EndoOperatesOn a ~ EndoOperatesOn b
-    , EndoOperatesOn a ~ EndoOperatesOn c
-    ) => AnEndo (a, b, c)
-  where
-    type EndoOperatesOn (a, b, c) = EndoOperatesOn a
-    anEndo    (a, b, c) = anEndo    a <> anEndo    b <> anEndo    c
-    aDualEndo (a, b, c) = aDualEndo a <> aDualEndo b <> aDualEndo c
-
-instance
-    ( AnEndo a1
-    , AnEndo a2
-    , AnEndo a3
-    , AnEndo a4
-    , EndoOperatesOn a1 ~ EndoOperatesOn a2
-    , EndoOperatesOn a1 ~ EndoOperatesOn a3
-    , EndoOperatesOn a1 ~ EndoOperatesOn a4
-    ) => AnEndo (a1, a2, a3, a4)
-  where
-    type EndoOperatesOn (a1, a2, a3, a4) = EndoOperatesOn a1
-    anEndo (a1, a2, a3, a4) = mconcat
-        [ anEndo a1
-        , anEndo a2
-        , anEndo a3
-        , anEndo a4
-        ]
-
-    aDualEndo (a1, a2, a3, a4) = mconcat
-        [ aDualEndo a1
-        , aDualEndo a2
-        , aDualEndo a3
-        , aDualEndo a4
-        ]
-
-instance
-    ( AnEndo a1
-    , AnEndo a2
-    , AnEndo a3
-    , AnEndo a4
-    , AnEndo a5
-    , EndoOperatesOn a1 ~ EndoOperatesOn a2
-    , EndoOperatesOn a1 ~ EndoOperatesOn a3
-    , EndoOperatesOn a1 ~ EndoOperatesOn a4
-    , EndoOperatesOn a1 ~ EndoOperatesOn a5
-    ) => AnEndo (a1, a2, a3, a4, a5)
-  where
-    type EndoOperatesOn (a1, a2, a3, a4, a5) = EndoOperatesOn a1
-
-    anEndo (a1, a2, a3, a4, a5) = mconcat
-        [ anEndo a1
-        , anEndo a2
-        , anEndo a3
-        , anEndo a4
-        , anEndo a5
-        ]
-
-    aDualEndo (a1, a2, a3, a4, a5) = mconcat
-        [ aDualEndo a1
-        , aDualEndo a2
-        , aDualEndo a3
-        , aDualEndo a4
-        , aDualEndo a5
-        ]
-
-instance
-    ( AnEndo a1
-    , AnEndo a2
-    , AnEndo a3
-    , AnEndo a4
-    , AnEndo a5
-    , AnEndo a6
-    , EndoOperatesOn a1 ~ EndoOperatesOn a2
-    , EndoOperatesOn a1 ~ EndoOperatesOn a3
-    , EndoOperatesOn a1 ~ EndoOperatesOn a4
-    , EndoOperatesOn a1 ~ EndoOperatesOn a5
-    , EndoOperatesOn a1 ~ EndoOperatesOn a6
-    ) => AnEndo (a1, a2, a3, a4, a5, a6)
-  where
-    type EndoOperatesOn (a1, a2, a3, a4, a5, a6) = EndoOperatesOn a1
-
-    anEndo (a1, a2, a3, a4, a5, a6) = mconcat
-        [ anEndo a1
-        , anEndo a2
-        , anEndo a3
-        , anEndo a4
-        , anEndo a5
-        , anEndo a6
-        ]
-
-    aDualEndo (a1, a2, a3, a4, a5, a6) = mconcat
-        [ aDualEndo a1
-        , aDualEndo a2
-        , aDualEndo a3
-        , aDualEndo a4
-        , aDualEndo a5
-        , aDualEndo a6
-        ]
-
-instance
-    ( AnEndo a1
-    , AnEndo a2
-    , AnEndo a3
-    , AnEndo a4
-    , AnEndo a5
-    , AnEndo a6
-    , AnEndo a7
-    , EndoOperatesOn a1 ~ EndoOperatesOn a2
-    , EndoOperatesOn a1 ~ EndoOperatesOn a3
-    , EndoOperatesOn a1 ~ EndoOperatesOn a4
-    , EndoOperatesOn a1 ~ EndoOperatesOn a5
-    , EndoOperatesOn a1 ~ EndoOperatesOn a6
-    , EndoOperatesOn a1 ~ EndoOperatesOn a7
-    ) => AnEndo (a1, a2, a3, a4, a5, a6, a7)
-  where
-    type EndoOperatesOn (a1, a2, a3, a4, a5, a6, a7) = EndoOperatesOn a1
-
-    anEndo (a1, a2, a3, a4, a5, a6, a7) = mconcat
-        [ anEndo a1
-        , anEndo a2
-        , anEndo a3
-        , anEndo a4
-        , anEndo a5
-        , anEndo a6
-        , anEndo a7
-        ]
-
-    aDualEndo (a1, a2, a3, a4, a5, a6, a7) = mconcat
-        [ aDualEndo a1
-        , aDualEndo a2
-        , aDualEndo a3
-        , aDualEndo a4
-        , aDualEndo a5
-        , aDualEndo a6
-        , aDualEndo a7
-        ]
-
-instance
-    ( AnEndo a1
-    , AnEndo a2
-    , AnEndo a3
-    , AnEndo a4
-    , AnEndo a5
-    , AnEndo a6
-    , AnEndo a7
-    , AnEndo a8
-    , EndoOperatesOn a1 ~ EndoOperatesOn a2
-    , EndoOperatesOn a1 ~ EndoOperatesOn a3
-    , EndoOperatesOn a1 ~ EndoOperatesOn a4
-    , EndoOperatesOn a1 ~ EndoOperatesOn a5
-    , EndoOperatesOn a1 ~ EndoOperatesOn a6
-    , EndoOperatesOn a1 ~ EndoOperatesOn a7
-    , EndoOperatesOn a1 ~ EndoOperatesOn a8
-    ) => AnEndo (a1, a2, a3, a4, a5, a6, a7, a8)
-  where
-    type EndoOperatesOn (a1, a2, a3, a4, a5, a6, a7, a8) = EndoOperatesOn a1
-
-    anEndo (a1, a2, a3, a4, a5, a6, a7, a8) = mconcat
-        [ anEndo a1
-        , anEndo a2
-        , anEndo a3
-        , anEndo a4
-        , anEndo a5
-        , anEndo a6
-        , anEndo a7
-        , anEndo a8
-        ]
-
-    aDualEndo (a1, a2, a3, a4, a5, a6, a7, a8) = mconcat
-        [ aDualEndo a1
-        , aDualEndo a2
-        , aDualEndo a3
-        , aDualEndo a4
-        , aDualEndo a5
-        , aDualEndo a6
-        , aDualEndo a7
-        , aDualEndo a8
-        ]
-
-instance
-    ( AnEndo a1
-    , AnEndo a2
-    , AnEndo a3
-    , AnEndo a4
-    , AnEndo a5
-    , AnEndo a6
-    , AnEndo a7
-    , AnEndo a8
-    , AnEndo a9
-    , EndoOperatesOn a1 ~ EndoOperatesOn a2
-    , EndoOperatesOn a1 ~ EndoOperatesOn a3
-    , EndoOperatesOn a1 ~ EndoOperatesOn a4
-    , EndoOperatesOn a1 ~ EndoOperatesOn a5
-    , EndoOperatesOn a1 ~ EndoOperatesOn a6
-    , EndoOperatesOn a1 ~ EndoOperatesOn a7
-    , EndoOperatesOn a1 ~ EndoOperatesOn a8
-    , EndoOperatesOn a1 ~ EndoOperatesOn a9
-    ) => AnEndo (a1, a2, a3, a4, a5, a6, a7, a8, a9)
-  where
-    type EndoOperatesOn (a1, a2, a3, a4, a5, a6, a7, a8, a9) = EndoOperatesOn a1
-
-    anEndo (a1, a2, a3, a4, a5, a6, a7, a8, a9) = mconcat
-        [ anEndo a1
-        , anEndo a2
-        , anEndo a3
-        , anEndo a4
-        , anEndo a5
-        , anEndo a6
-        , anEndo a7
-        , anEndo a8
-        , anEndo a9
-        ]
-
-    aDualEndo (a1, a2, a3, a4, a5, a6, a7, a8, a9) = mconcat
-        [ aDualEndo a1
-        , aDualEndo a2
-        , aDualEndo a3
-        , aDualEndo a4
-        , aDualEndo a5
-        , aDualEndo a6
-        , aDualEndo a7
-        , aDualEndo a8
-        , aDualEndo a9
-        ]
-
-instance
-    ( AnEndo a1
-    , AnEndo a2
-    , AnEndo a3
-    , AnEndo a4
-    , AnEndo a5
-    , AnEndo a6
-    , AnEndo a7
-    , AnEndo a8
-    , AnEndo a9
-    , AnEndo a10
-    , EndoOperatesOn a1 ~ EndoOperatesOn a2
-    , EndoOperatesOn a1 ~ EndoOperatesOn a3
-    , EndoOperatesOn a1 ~ EndoOperatesOn a4
-    , EndoOperatesOn a1 ~ EndoOperatesOn a5
-    , EndoOperatesOn a1 ~ EndoOperatesOn a6
-    , EndoOperatesOn a1 ~ EndoOperatesOn a7
-    , EndoOperatesOn a1 ~ EndoOperatesOn a8
-    , EndoOperatesOn a1 ~ EndoOperatesOn a9
-    , EndoOperatesOn a1 ~ EndoOperatesOn a10
-    ) => AnEndo (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
-  where
-    type EndoOperatesOn (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) = EndoOperatesOn a1
-
-    anEndo (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) = mconcat
-        [ anEndo a1
-        , anEndo a2
-        , anEndo a3
-        , anEndo a4
-        , anEndo a5
-        , anEndo a6
-        , anEndo a7
-        , anEndo a8
-        , anEndo a9
-        , anEndo a10
-        ]
-
-    aDualEndo (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) = mconcat
-        [ aDualEndo a1
-        , aDualEndo a2
-        , aDualEndo a3
-        , aDualEndo a4
-        , aDualEndo a5
-        , aDualEndo a6
-        , aDualEndo a7
-        , aDualEndo a8
-        , aDualEndo a9
-        , aDualEndo a10
-        ]
-
--- }}} Instances For Tuples ---------------------------------------------------
--- }}} AnEndo Type Class ------------------------------------------------------
-
--- {{{ Utility Functions ------------------------------------------------------
+-- 'FoldEndoArgs' args => args ':->' 'Endo' String
+-- ('FoldEndoArgs' args, 'Result' args ~ 'Endo' String) => args
+-- @
+type args :-> r = (Result args ~ r) => args
 
 -- | Variant of function @('Data.Function.$') :: (a -> b) -> a -> b@, from
 -- "Data.Function" module, but with fixity as
@@ -833,39 +433,7 @@
 (<&$>) = fmap
 infixl 1 <&$>
 
--- | Use 'Endo' (possibly result of 'foldEndo') and use it to create value of
--- different type.
---
--- Examples:
---
--- @
--- 'embedEndoWith' 'Control.Monad.Trans.Writer.Lazy.tell'
---     :: (Monad m, 'AnEndo' e, w ~ 'EndoOperatesOn' e)
---     => e
---     -> 'Control.Monad.Trans.Writer.Lazy.WriterT' ('Endo' w) m ()
---
--- 'embedEndoWith' 'Control.Monad.Trans.State.Lazy.modify'
---     :: (Monad m, 'AnEndo' e, s ~ 'EndoOperatesOn' e)
---     => e
---     -> 'Control.Monad.Trans.State.Lazy.StateT' s m ()
--- @
---
--- See also 'embedDualEndoWith'.
-embedEndoWith :: (AnEndo e, EndoOperatesOn e ~ a)
-    => (Endo a -> b)
-    -- ^ Embedding function.
-    -> e -> b
-embedEndoWith = (. anEndo)
-
--- | Dual to 'embedEndoWith', which uses 'aDualEndo' instead of 'anEndo'.
-embedDualEndoWith
-    :: (AnEndo e, EndoOperatesOn e ~ a)
-    => (Dual (Endo a) -> b)
-    -- ^ Embedding function.
-    -> e -> b
-embedDualEndoWith = (. aDualEndo)
-
--- }}} Utility Functions ------------------------------------------------------
+-- }}} Utility Functions and Types --------------------------------------------
 
 -- $basicIdea
 --
@@ -873,7 +441,7 @@
 --
 -- @
 -- data Verbosity = Silent | Normal | Verbose | Annoying
---   deriving (Bounded, Data, Enum, Eq, Ord, Show, Typeable)
+--   deriving (Show)
 --
 -- data Config = Config
 --     { _verbosity :: Verbosity
diff --git a/src/Data/Monoid/Endo/FromEndo.hs b/src/Data/Monoid/Endo/FromEndo.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Monoid/Endo/FromEndo.hs
@@ -0,0 +1,194 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE TypeFamilies #-}
+-- |
+-- Module:       $HEADER$
+-- Description:  Convert endomorphism in to a value.
+-- Copyright:    (c) 2015, Peter Trško
+-- License:      BSD3
+--
+-- Maintainer:   peter.trsko@gmail.com
+-- Stability:    experimental
+-- Portability:  NoImplicitPrelude
+--
+-- Convert endomorphism in to a value.
+module Data.Monoid.Endo.FromEndo
+    (
+    -- * Convert Endo to a Value
+      FromEndo(..)
+    , fromEndoWith
+    , fromEndoWithF
+    , fromDualEndoWith
+    , fromDualEndoWithF
+    , fromEndoTo
+    , fromDualEndoTo
+    )
+  where
+
+import Control.Monad (Monad)
+import Data.Function ((.), id)
+import Data.Functor (Functor(fmap))
+import Data.Monoid (Dual(Dual, getDual), Endo(Endo, appEndo), Monoid)
+
+import Control.Monad.Trans.Reader (ReaderT)
+import Control.Monad.Trans.Reader as Reader (asks)
+import Control.Monad.Trans.RWS.Lazy as Lazy (RWST)
+import Control.Monad.Trans.RWS.Lazy as Lazy.RWS (modify)
+import Control.Monad.Trans.RWS.Strict as Strict (RWST)
+import Control.Monad.Trans.RWS.Strict as Strict.RWS (modify)
+import Control.Monad.Trans.State.Lazy as Lazy (StateT)
+import Control.Monad.Trans.State.Lazy as Lazy.State (modify)
+import Control.Monad.Trans.State.Strict as Strict (StateT)
+import Control.Monad.Trans.State.Strict as Strict.State (modify)
+
+
+-- | Type class provides functionality for converting @'Endo' b@ and @'Dual'
+-- ('Endo' b)@ in to some type @a@. Type @b@, on which endomorphism operates,
+-- is implied by type @a@, but generally aren't the same type. In other words
+-- it is dual type class to 'Data.Monoid.Endo.AnEndo'.
+class FromEndo a where
+    type EndoOperatedOn a
+
+    -- | Convert endomorphism in to a value of type @a@.
+    fromEndo :: Endo (EndoOperatedOn a) -> a
+
+    -- | Provided default implementation:
+    --
+    -- @
+    -- 'fromDualEndo' = 'fromEndo' '.' 'getDual'
+    -- @
+    fromDualEndo :: Dual (Endo (EndoOperatedOn a)) -> a
+    fromDualEndo = fromEndo . getDual
+
+#ifdef HAVE_MINIMAL_PRAGMA
+    {-# MINIMAL fromEndo #-}
+#endif
+
+instance FromEndo (a -> a) where
+    type EndoOperatedOn (a -> a) = a
+
+    fromEndo = appEndo
+    fromDualEndo = appEndo . getDual
+
+instance FromEndo (Endo a) where
+    type EndoOperatedOn (Endo a) = a
+
+    fromEndo = id
+    fromDualEndo = getDual
+
+instance FromEndo e => FromEndo (Dual e) where
+    type EndoOperatedOn (Dual e) = EndoOperatedOn e
+
+    fromEndo = Dual . fromEndo
+    fromDualEndo = Dual . fromDualEndo
+
+-- {{{ Transformers instances for FromEndo ------------------------------------
+
+-- | Retrieve environment modified by endomorphism.
+--
+-- @
+-- 'fromEndo' ('Endo' f) = 'Reader.asks' f
+-- @
+instance Monad f => FromEndo (ReaderT r f r) where
+    type EndoOperatedOn (ReaderT r f r) = r
+
+    fromEndo (Endo f) = Reader.asks f
+
+-- | Modify state.
+--
+-- @
+-- 'fromEndo' ('Endo' f) = 'Lazy.RWS.modify' f
+-- @
+instance (Monoid w, Monad f) => FromEndo (Lazy.RWST r w s f ()) where
+    type EndoOperatedOn (Lazy.RWST r w s f ()) = s
+
+    fromEndo (Endo f) = Lazy.RWS.modify f
+
+-- | Modify state.
+--
+-- @
+-- 'fromEndo' ('Endo' f) = 'Strict.RWS.modify' f
+-- @
+instance (Monoid w, Monad f) => FromEndo (Strict.RWST r w s f ()) where
+    type EndoOperatedOn (Strict.RWST r w s f ()) = s
+
+    fromEndo (Endo f) = Strict.RWS.modify f
+
+-- | Modify state.
+--
+-- @
+-- 'fromEndo' ('Endo' f) = 'Lazy.State.modify' f
+-- @
+instance Monad f => FromEndo (Lazy.StateT s f ()) where
+    type EndoOperatedOn (Lazy.StateT s f ()) = s
+
+    fromEndo (Endo f) = Lazy.State.modify f
+
+-- | Modify state.
+--
+-- @
+-- 'fromEndo' ('Endo' f) = 'Strict.State.modify' f
+-- @
+instance Monad f => FromEndo (Strict.StateT s f ()) where
+    type EndoOperatedOn (Strict.StateT s f ()) = s
+
+    fromEndo (Endo f) = Strict.State.modify f
+
+-- }}} Transformers instances for FromEndo ------------------------------------
+
+-- | In a lot of cases it is necessary to evaluate result of 'fromEndo'.
+-- Example:
+--
+-- >>> fromEndoWith ((`runState` def) :: State Int () -> ((), Int)) (Endo (+10))
+-- ((), 10)
+--
+-- Following property holds:
+--
+-- @
+-- 'fromEndoWith' 'id' = 'fromEndo'
+-- @
+--
+-- See also 'fromDualEndoWith'.
+fromEndoWith :: (FromEndo a, EndoOperatedOn a ~ c) => (a -> b) -> Endo c -> b
+fromEndoWith = (. fromEndo)
+
+-- | Same as 'fromEndoWith', but deals with 'Endo' wrapped inside a 'Functor'.
+fromEndoWithF
+    :: (Functor f, FromEndo a, EndoOperatedOn a ~ c)
+    => (f a -> b) -> f (Endo c) -> b
+fromEndoWithF = (. fmap fromEndo)
+
+-- | In a lot of cases it is necessary to evaluate result of 'fromDualEndo'.
+-- Example:
+--
+-- >>> fromEndoWith ((`runState` def) :: State Int () -> ((), Int)) (Dual (Endo (+10)))
+-- ((), 10)
+--
+-- Following property holds:
+--
+-- @
+-- 'fromDualEndoWith' 'id' = 'fromDualEndo'
+-- @
+--
+-- See also 'fromEndoWith'.
+fromDualEndoWith
+    :: (FromEndo a, EndoOperatedOn a ~ c) => (a -> b) -> Dual (Endo c) -> b
+fromDualEndoWith = (. fromDualEndo)
+
+-- | Same as 'fromDualEndoWith', but deals with @'Dual' 'Endo'@ wrapped inside
+-- a 'Functor'.
+fromDualEndoWithF
+    :: (Functor f, FromEndo a, EndoOperatedOn a ~ c)
+    => (f a -> b) -> f (Dual (Endo c)) -> b
+fromDualEndoWithF = (. fmap fromDualEndo)
+
+-- | Variant of 'fromEndo' that takes type restriction on the result type @a@
+-- as an argument.
+fromEndoTo :: FromEndo a => Endo (EndoOperatedOn a) -> proxy a -> a
+fromEndoTo e _ = fromEndo e
+
+-- | Variant of 'fromDualEndo' that takes type restriction on the result type
+-- @a@ as an argument.
+fromDualEndoTo :: FromEndo a => Dual (Endo (EndoOperatedOn a)) -> proxy a -> a
+fromDualEndoTo e _ = fromDualEndo e
