emgm-0.3.1: Extensible and Modular Generics for the MassesSource codeContentsIndex
Generics.EMGM.Functions.Everywhere
Portabilitynon-portable
Stabilityexperimental
Maintainergenerics@haskell.org
Description

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
Synopsis
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) where
     rep = Everywhere app
       where
         app f x =
           case x of
             Val v1 -> f (Val (selEverywhere rep f v1))
             Rec v1 -> f (Rec (selEverywhere rep f v1))

Note the requirement of overlapping instances.

This instance is triggered when the function type (the first T a in Rep (Everywhere (T a)) (T a)) matches some value type (the second T a) contained within the argument to everywhere.

Constructors
Everywhere
selEverywhere :: (a -> a) -> b -> b
show/hide Instances
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)
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 == x
   True

Note the type annotations. Since numerical constants have the type Num a => a, you may need to give explicit types. Also, the function \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 = ...
   instance Rep (Everywhere' U) U where
     rep = Everywhere' ($)

Note the requirement of overlapping instances.

This instance is triggered when the function type (the first U in Rep (Everywhere U) U) matches some value type (the second U) contained within the argument to everywhere'.

Constructors
Everywhere'
selEverywhere' :: (a -> a) -> b -> b
show/hide Instances
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'.

Produced by Haddock version 2.4.2