newtype-0.2: A typeclass and set of functions for working with newtypes.

Safe HaskellSafe
LanguageHaskell98

Control.Newtype

Description

The Newtype typeclass and related functions: op, ala, ala', under. Primarly pulled from Conor McBride's Epigram work. Some examples:

ala Sum foldMap [1,2,3,4] -- foldMaps the list ala the Sum newtype. This results in 10.
ala Product foldMap [1,2,3,4] -- foldMaps the list ala the Product newtype. This results in 24.
ala Endo foldMap [(+1), (+2), (subtract 1), (*2)] 3 -- foldMaps the list ala the Endo newtype. This results in 8.

NB: foldMap is a generalized mconcatMap which is a generalized concatMap.

This package includes Newtype instances for all the (non-GHC/foreign) newtypes in base (as seen in the examples). However, there are neat things you can do with this with any newtype and you should definitely define your own Newtype instances for the power of this library. For example, see ala Cont traverse, with the proper Newtype instance for Cont.

Synopsis

Documentation

class Newtype n o | n -> o where #

Given a newtype n, we will always have the same unwrapped type o, meaning we can represent this with a fundep n -> o.

Any instance of this class just needs to let pack equal to the newtype's constructor, and let unpack destruct the newtype with pattern matching.

Methods

pack :: o -> n #

unpack :: n -> o #

Instances
Newtype All Bool # 
Instance details

Defined in Control.Newtype

Methods

pack :: Bool -> All #

unpack :: All -> Bool #

Newtype Any Bool # 
Instance details

Defined in Control.Newtype

Methods

pack :: Bool -> Any #

unpack :: Any -> Bool #

Newtype (Sum a) a # 
Instance details

Defined in Control.Newtype

Methods

pack :: a -> Sum a #

unpack :: Sum a -> a #

Newtype (Product a) a # 
Instance details

Defined in Control.Newtype

Methods

pack :: a -> Product a #

unpack :: Product a -> a #

Newtype (ZipList a) [a] # 
Instance details

Defined in Control.Newtype

Methods

pack :: [a] -> ZipList a #

unpack :: ZipList a -> [a] #

Newtype (First a) (Maybe a) # 
Instance details

Defined in Control.Newtype

Methods

pack :: Maybe a -> First a #

unpack :: First a -> Maybe a #

Newtype (Last a) (Maybe a) # 
Instance details

Defined in Control.Newtype

Methods

pack :: Maybe a -> Last a #

unpack :: Last a -> Maybe a #

Newtype (Endo a) (a -> a) # 
Instance details

Defined in Control.Newtype

Methods

pack :: (a -> a) -> Endo a #

unpack :: Endo a -> a -> a #

Newtype (WrappedMonad m a) (m a) # 
Instance details

Defined in Control.Newtype

Methods

pack :: m a -> WrappedMonad m a #

unpack :: WrappedMonad m a -> m a #

ArrowApply a => Newtype (ArrowMonad a b) (a () b) # 
Instance details

Defined in Control.Newtype

Methods

pack :: a () b -> ArrowMonad a b #

unpack :: ArrowMonad a b -> a () b #

Newtype (Const a x) a # 
Instance details

Defined in Control.Newtype

Methods

pack :: a -> Const a x #

unpack :: Const a x -> a #

Newtype (WrappedArrow a b c) (a b c) # 
Instance details

Defined in Control.Newtype

Methods

pack :: a b c -> WrappedArrow a b c #

unpack :: WrappedArrow a b c -> a b c #

Newtype (Kleisli m a b) (a -> m b) # 
Instance details

Defined in Control.Newtype

Methods

pack :: (a -> m b) -> Kleisli m a b #

unpack :: Kleisli m a b -> a -> m b #

op :: Newtype n o => (o -> n) -> n -> o #

This function serves two purposes:

  1. Giving you the unpack of a newtype without you needing to remember the name.
  2. Showing that the first parameter is completely ignored on the value level, meaning the only reason you pass in the constructor is to provide type information. Typeclasses sure are neat.

ala :: (Newtype n o, Newtype n' o') => (o -> n) -> ((o -> n) -> b -> n') -> b -> o' #

The workhorse of the package. Given a pack and a "higher order function", it handles the packing and unpacking, and just sends you back a regular old function, with the type varying based on the hof you passed.

The reason for the signature of the hof is due to ala not caring about structure. To illustrate why this is important, another function in this package is under. It is not extremely useful; under2 might be more useful (with e.g., mappend), but then we already digging the trench of "What about under3? under4?". The solution utilized here is to just hand off the "packer" to the hof. That way your structure can be imposed in the hof, whatever you may want it to be (e.g., List, Traversable).

ala' :: (Newtype n o, Newtype n' o') => (o -> n) -> ((a -> n) -> b -> n') -> (a -> o) -> b -> o' #

This is the original function seen in Conor McBride's work. The way it differs from the ala function in this package, is that it provides an extra hook into the "packer" passed to the hof. However, this normally ends up being id, so ala wraps this function and passes id as the final parameter by default. If you want the convenience of being able to hook right into the hof, you may use this function.

under :: (Newtype n o, Newtype n' o') => (o -> n) -> (n -> n') -> o -> o' #

A very simple operation involving running the function 'under' the newtype. Suffers from the problems mentioned in the ala function's documentation.

over :: (Newtype n o, Newtype n' o') => (o -> n) -> (o -> o') -> n -> n' #

The opposite of under. I.e., take a function which works on the underlying types, and switch it to a function that works on the newtypes.

underF :: (Newtype n o, Newtype n' o', Functor f) => (o -> n) -> (f n -> f n') -> f o -> f o' #

under lifted into a Functor.

overF :: (Newtype n o, Newtype n' o', Functor f) => (o -> n) -> (f o -> f o') -> f n -> f n' #

over lifted into a Functor.