Copyright | (c) 2014-2016, Peter Trško |
---|---|
License | BSD3 |
Maintainer | peter.trsko@gmail.com |
Stability | experimental |
Portability | CPP, DeriveDataTypeable, DeriveGeneric, FlexibleInstances, NoImplicitPrelude, TypeFamilies |
Safe Haskell | None |
Language | Haskell2010 |
Conversion of values in to endomorphisms.
- class AnEndo a where
- type EndoOperatesOn a
- anEndo :: a -> Endo (EndoOperatesOn a)
- aDualEndo :: a -> Dual (Endo (EndoOperatesOn a))
- newtype WrappedFoldable f a = WrapFoldable {
- getFoldable :: f a
- embedEndoWith :: (AnEndo e, EndoOperatesOn e ~ a) => (Endo a -> b) -> e -> b
- embedDualEndoWith :: (AnEndo e, EndoOperatesOn e ~ a) => (Dual (Endo a) -> b) -> e -> b
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 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.
instanceAnEndo
(Proxy
a) where typeEndoOperatesOn
(Proxy
a) = aanEndo
_ =mempty
-- = Endoid
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.
instanceAnEndo
a =>AnEndo
(Maybe
a) where typeEndoOperatesOn
(Maybe
a) =EndoOperatesOn
aanEndo
Nothing
=mempty
-- = Endoid
anEndo
(Just
e) =anEndo
e -- Definition ofaDualEndo
is analogous.
Instance for Maybe
lets us conditionally inject endomorphism in to a
folding chain.
instanceAnEndo
a =>AnEndo
(Identity
a) where typeEndoOperatesOn
(Identity
a) =EndoOperatesOn
aanEndo
(Identity
e) =anEndo
eaDualEndo
(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.
type EndoOperatesOn a Source
Extract type on which endomorphism operates, e.g. for
(
it would be Endo
a)a
.
anEndo :: a -> Endo (EndoOperatesOn a) Source
aDualEndo :: a -> Dual (Endo (EndoOperatesOn a)) 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, (
is just an example of
endomorphism representation, any E
a)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.
WrapFoldable | |
|
Monad f => Monad (WrappedFoldable f) Source | |
Functor f => Functor (WrappedFoldable f) Source | |
Applicative f => Applicative (WrappedFoldable f) Source | |
Foldable f => Foldable (WrappedFoldable f) Source | |
Traversable f => Traversable (WrappedFoldable f) Source | |
Generic1 (WrappedFoldable f) Source | |
(Data (f a), Typeable (* -> *) f, Typeable * a) => Data (WrappedFoldable f a) Source | |
Read (f a) => Read (WrappedFoldable f a) Source | |
Show (f a) => Show (WrappedFoldable f a) Source | |
Generic (WrappedFoldable f a) Source | |
(Foldable f, AnEndo a) => AnEndo (WrappedFoldable f a) Source | |
type Rep1 (WrappedFoldable f) Source | |
type Rep (WrappedFoldable f a) Source | |
type EndoOperatesOn (WrappedFoldable f a) = EndoOperatesOn a Source |
Utility Functions and Types
:: (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
.
:: (AnEndo e, EndoOperatesOn e ~ a) | |
=> (Dual (Endo a) -> b) | Embedding function. |
-> e | |
-> b |
Dual to embedEndoWith
, which uses aDualEndo
instead of anEndo
.