endo-0.3.0.1: Endomorphism utilities.

Copyright(c) 2014-2016, Peter Trško
LicenseBSD3
Maintainerpeter.trsko@gmail.com
Stabilityexperimental
PortabilityCPP, DeriveDataTypeable, DeriveGeneric, FlexibleInstances, NoImplicitPrelude, TypeFamilies
Safe HaskellNone
LanguageHaskell2010

Data.Monoid.Endo.AnEndo

Contents

Description

Conversion of values in to endomorphisms.

Synopsis

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.

class AnEndo a where Source

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.

Minimal complete definition

anEndo | aDualEndo

Associated Types

type EndoOperatesOn a Source

Extract type on which endomorphism operates, e.g. for (Endo a) it would be a.

Methods

anEndo :: a -> Endo (EndoOperatesOn a) Source

Convert value encoding (a -> a) in to Endo. Default implementation:

anEndo = getDual . aDualEndo

aDualEndo :: a -> Dual (Endo (EndoOperatesOn a)) Source

Dual to anEndo. Default implementation:

aDualEndo = Dual . anEndo

Instances

AnEndo a => AnEndo [a] Source 
AnEndo a => AnEndo (Identity a) Source 
AnEndo (Endo a) Source 
AnEndo a => AnEndo (Maybe a) Source 
AnEndo (a -> a) Source 
(AnEndo a, AnEndo b, (~) * (EndoOperatesOn a) (EndoOperatesOn b)) => AnEndo (a, b) Source 
AnEndo (Proxy * a) Source

Constructs identity endomorphism for specified phantom type.

(Foldable f, AnEndo a) => AnEndo (Reverse f a) Source

Fold in reverese order.

(Foldable f, AnEndo a) => AnEndo (WrappedFoldable f a) Source 
(AnEndo a, AnEndo b, AnEndo c, (~) * (EndoOperatesOn a) (EndoOperatesOn b), (~) * (EndoOperatesOn a) (EndoOperatesOn c)) => AnEndo (a, b, c) Source 
(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) Source 
(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) Source 
(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) Source 
(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) Source 
(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) Source 
(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) Source 
(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) Source 

WrappedFoldable

Newtype WrappedFoldable allows us to use anEndo, aDualEndo, foldEndo, and 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 (E a) -> Endo a
\vectorOfEndos -> foldEndo (WrappedFoldable vectorOfEndos)
    :: FoldEndoArgs => Vector (E a) -> args

Note that the Vector is just one of possible Foldable data types that may be used here. Also, (E a) is just an example of endomorphism representation, any AnEndo instance can be used.

newtype WrappedFoldable f a Source

Wrapper for Foldable types. Used to provide instances that work for all Foldable types without the need for OverlappingInstances language extension.

Constructors

WrapFoldable 

Fields

getFoldable :: f a
 

Utility Functions and Types

embedEndoWith Source

Arguments

:: (AnEndo e, EndoOperatesOn e ~ a) 
=> (Endo a -> b)

Embedding function.

-> e 
-> b 

Use Endo (possibly result of foldEndo) and use it to create value of different type.

Examples:

embedEndoWith tell
    :: (Monad m, AnEndo e, w ~ EndoOperatesOn e)
    => e
    -> WriterT (Endo w) m ()

embedEndoWith (modify . appEndo)
    :: (Monad m, AnEndo e, s ~ EndoOperatesOn e)
    => e
    -> StateT s m ()

See also embedDualEndoWith.

embedDualEndoWith Source

Arguments

:: (AnEndo e, EndoOperatesOn e ~ a) 
=> (Dual (Endo a) -> b)

Embedding function.

-> e 
-> b 

Dual to embedEndoWith, which uses aDualEndo instead of anEndo.