Portability | non-portable |
---|---|
Stability | experimental |
Maintainer | generics@haskell.org |
Summary: Generic functions that apply a transformation at every location of one type in a value of a possibly different type.
The functions everywhere
and everywhere'
have exactly the same type, but
they apply the transformation in different fashions. everywhere
uses
bottom-up application while everywhere'
uses a top-down approach. This may
make a difference if you have recursive datatypes or use nested pattern
matching in the higher-order function.
These functions are very similar to others with the same names in the "Scrap
Your Boilerplate" library (syb
package). The SYB functions use rank-2
types, while the EMGM functions use a single class constraint. Compare the
types of the following:
-- SYB everywhere :: (forall a. Data a => a -> a) -> forall a. Data a => a -> a
-- EMGM everywhere :: (Rep (Everywhere a) b) => (a -> a) -> b -> b
- newtype Everywhere a b = Everywhere {
- selEverywhere :: (a -> a) -> b -> b
- everywhere :: Rep (Everywhere a) b => (a -> a) -> b -> b
- newtype Everywhere' a b = Everywhere' {
- selEverywhere' :: (a -> a) -> b -> b
- everywhere' :: Rep (Everywhere' a) b => (a -> a) -> b -> b
Documentation
newtype Everywhere a b Source
The type of a generic function that takes a function of one type, a value of another type, and returns a value of the value type.
For datatypes to work with Everywhere, a special instance must be given. This
instance is trivial to write. For a non-recursive type, the instance is the
same as described for Everywhere'
. For a recursive type T
, the Rep
instance looks like this:
{-# LANGUAGE OverlappingInstances #-}
data T a = Val a | Rec (T a)
instance (Rep
(Everywhere (T a)) (T a),Rep
(Everywhere (T a)) a) =>Rep
(Everywhere (T a)) (T a) whererep
= Everywhere app where app f x = case x of Val v1 -> f (Val (selEverywhererep
f v1)) Rec v1 -> f (Rec (selEverywhererep
f v1))
Note the requirement of overlapping instances.
This instance is triggered when the function type (the first T a
in
) matches some value type (the second Rep
(Everywhere (T a)) (T a)T a
)
contained within the argument to everywhere
.
Everywhere | |
|
Generic (Everywhere a) | |
Rep (Everywhere Bool) Bool | |
Rep (Everywhere Char) Char | |
Rep (Everywhere Double) Double | |
Rep (Everywhere Float) Float | |
Rep (Everywhere Int) Int | |
Rep (Everywhere Integer) Integer | |
Rep (Everywhere ()) () | |
Rep (Everywhere [a]) a => Rep (Everywhere [a]) [a] | |
(Integral a, Rep (Everywhere (Ratio a)) a) => Rep (Everywhere (Ratio a)) (Ratio a) | |
Rep (Everywhere (Maybe a)) a => Rep (Everywhere (Maybe a)) (Maybe a) | |
(Rep (Everywhere (Either a b)) a, Rep (Everywhere (Either a b)) b) => Rep (Everywhere (Either a b)) (Either a b) | |
(Rep (Everywhere (a, b)) a, Rep (Everywhere (a, b)) b) => Rep (Everywhere (a, b)) (a, b) | |
(Rep (Everywhere (a, b, c)) a, Rep (Everywhere (a, b, c)) b, Rep (Everywhere (a, b, c)) c) => Rep (Everywhere (a, b, c)) (a, b, c) | |
(Rep (Everywhere (a, b, c, d)) a, Rep (Everywhere (a, b, c, d)) b, Rep (Everywhere (a, b, c, d)) c, Rep (Everywhere (a, b, c, d)) d) => Rep (Everywhere (a, b, c, d)) (a, b, c, d) | |
(Rep (Everywhere (a, b, c, d, e)) a, Rep (Everywhere (a, b, c, d, e)) b, Rep (Everywhere (a, b, c, d, e)) c, Rep (Everywhere (a, b, c, d, e)) d, Rep (Everywhere (a, b, c, d, e)) e) => Rep (Everywhere (a, b, c, d, e)) (a, b, c, d, e) | |
(Rep (Everywhere (a, b, c, d, e, f)) a, Rep (Everywhere (a, b, c, d, e, f)) b, Rep (Everywhere (a, b, c, d, e, f)) c, Rep (Everywhere (a, b, c, d, e, f)) d, Rep (Everywhere (a, b, c, d, e, f)) e, Rep (Everywhere (a, b, c, d, e, f)) f) => Rep (Everywhere (a, b, c, d, e, f)) (a, b, c, d, e, f) | |
(Rep (Everywhere (a, b, c, d, e, f, h)) a, Rep (Everywhere (a, b, c, d, e, f, h)) b, Rep (Everywhere (a, b, c, d, e, f, h)) c, Rep (Everywhere (a, b, c, d, e, f, h)) d, Rep (Everywhere (a, b, c, d, e, f, h)) e, Rep (Everywhere (a, b, c, d, e, f, h)) f, Rep (Everywhere (a, b, c, d, e, f, h)) h) => Rep (Everywhere (a, b, c, d, e, f, h)) (a, b, c, d, e, f, h) |
everywhere :: Rep (Everywhere a) b => (a -> a) -> b -> bSource
Apply a transformation a -> a
to values of type a
within the argument
of type b
in a bottom-up manner. Values that do not have type a
are
passed through id
.
everywhere
works by searching the datatype b
for values that are the same
type as the function argument type a
. Here are some examples using the
datatype declared in the documentation for Everywhere
.
ghci> let f t = case t of { Val i -> Val (i+(1::Int
)); other -> other } ghci> everywhere f (Val (1::Int
)) Val 2 ghci> everywhere f (Rec (Rec (Val (1::Int
)))) Rec (Rec (Val 2))
ghci> let x = [Left
1,Right
'a',Left
2] :: [Either
Int
Char
] ghci> everywhere (*(3::Int
)) x [Left
3,Right
'a',Left
6] ghci> everywhere (\x -> x ::Float
) x == xTrue
Note the type annotations. Since numerical constants have the type
, you may need to give explicit types. Also, the function Num
a
=> a\x -> x
has
type a -> a
, but we need to give it some non-polymorphic type here. By
design, there is no connection that can be inferred between the value type
and the function type.
everywhere
only works if there is an instance for the return type as
described in the newtype
.
Everywhere
newtype Everywhere' a b Source
This type servers the same purpose as Everywhere
, except that Rep
instances are designed to be top-down instead of bottom-up. That means, given
any type U
(recursive or not), the Rep
instance looks like this:
{-# LANGUAGE OverlappingInstances #-}
data U = ...
instanceRep
(Everywhere' U) U whererep
= Everywhere' ($)
Note the requirement of overlapping instances.
This instance is triggered when the function type (the first U
in
) matches some value type (the second Rep
(Everywhere U) UU
) contained within
the argument to everywhere'
.
Everywhere' | |
|
Generic (Everywhere' a) | |
Rep (Everywhere' Bool) Bool | |
Rep (Everywhere' Char) Char | |
Rep (Everywhere' Double) Double | |
Rep (Everywhere' Float) Float | |
Rep (Everywhere' Int) Int | |
Rep (Everywhere' Integer) Integer | |
Rep (Everywhere' ()) () | |
Rep (Everywhere' [a]) [a] | |
Rep (Everywhere' (Ratio a)) (Ratio a) | |
Rep (Everywhere' (Maybe a)) (Maybe a) | |
Rep (Everywhere' (Either a b)) (Either a b) | |
Rep (Everywhere' (a, b)) (a, b) | |
Rep (Everywhere' (a, b, c)) (a, b, c) | |
Rep (Everywhere' (a, b, c, d)) (a, b, c, d) | |
Rep (Everywhere' (a, b, c, d, e)) (a, b, c, d, e) | |
Rep (Everywhere' (a, b, c, d, e, f)) (a, b, c, d, e, f) | |
Rep (Everywhere' (a, b, c, d, e, f, h)) (a, b, c, d, e, f, h) |
everywhere' :: Rep (Everywhere' a) b => (a -> a) -> b -> bSource
Apply a transformation a -> a
to values of type a
within the argument
of type b
in a top-down manner. Values that do not have type a
are passed
through id
.
everywhere'
is the same as everywhere
with the exception of recursive
datatypes. For example, compare the example used in the documentation for
everywhere
with the following.
ghci> let f t = case t of { Val i -> Val (i+(1::Int
)); other -> other } ghci> everywhere' f (Val (1::Int
)) Val 2 ghci> everywhere' f (Rec (Rec (Val (1::Int
)))) Rec (Rec (Val 1))
everywhere'
only works if there is an instance for the return type as
described in the newtype
.
Everywhere'