    Rank 2 Classes
    ==============

    ### The standard constructor type classes in the parallel rank-2 universe ###

    The rank2 package exports module `Rank2`, meant to be imported qualified like this:

    ~~~ {.haskell}
    {-# LANGUAGE RankNTypes, TemplateHaskell, TypeOperators #-}
    module MyModule where
    import qualified Rank2
    import qualified Rank2.TH
    ~~~

    Several more imports for the examples...

    ~~~ {.haskell}
    import Data.Functor.Classes (Show1, showsPrec1)
    import Data.Functor.Identity (Identity(..))
    import Data.Functor.Const (Const(..))
    import Data.List (find)
    ~~~

    The `Rank2` import will make available the following type classes:

      * [Rank2.Functor](http://hackage.haskell.org/package/rank2classes/docs/Rank2.html#t:Functor)
      * [Rank2.Apply](http://hackage.haskell.org/package/rank2classes/docs/Rank2.html#t:Apply)
      * [Rank2.Applicative](http://hackage.haskell.org/package/rank2classes/docs/Rank2.html#t:Applicative)
      * [Rank2.Foldable](http://hackage.haskell.org/package/rank2classes/docs/Rank2.html#t:Foldable)
      * [Rank2.Traversable](http://hackage.haskell.org/package/rank2classes/docs/Rank2.html#t:Traversable)
      * [Rank2.Distributive](http://hackage.haskell.org/package/rank2classes/docs/Rank2.html#t:Distributive)
      * [Rank2.Logistic](http://hackage.haskell.org/package/rank2classes/docs/Rank2.html#t:Logistic)

    The methods of these type classes all have rank-2 types. The class instances are data types of kind `(k -> *) -> *`,
    one example of which would be a database record with different field types but all wrapped by the same type
    constructor:

    ~~~ {.haskell}
    data Person f = Person{
       forall (f :: * -> *). Person f -> f String
    name           :: f String,
       forall (f :: * -> *). Person f -> f Int
    age            :: f Int,
       forall (f :: * -> *). Person f -> f (Maybe PersonVerified)
    mother, forall (f :: * -> *). Person f -> f (Maybe PersonVerified)
    father :: f (Maybe PersonVerified)
       }
    ~~~

    By wrapping each field we have declared a generalized record type. It can made to play different roles by switching the
    value of the parameter `f`. Some examples would be

    ~~~ {.haskell}
    type PersonVerified = Person Identity
    type PersonText = Person (Const String)
    type PersonWithErrors = Person (Either String)
    type PersonDatabase = [PersonVerified]
    type PersonDatabaseByColumns = Person []
    ~~~

    If you wish to have the standard [Eq](http://hackage.haskell.org/package/base/docs/Data-Eq.html#t:Eq) and
    [Show](http://hackage.haskell.org/package/base/docs/Text-Show.html#t:Show) instances for a record type like `Person`,
    it's best if they refer to the
    [Eq1](http://hackage.haskell.org/package/base-4.9.1.0/docs/Data-Functor-Classes.html#t:Eq1) and
    [Show1](http://hackage.haskell.org/package/base-4.9.1.0/docs/Data-Functor-Classes.html#t:Show1) instances for its
    parameter `f`:

    ~~~ {.haskell}
    instance Show1 f => Show (Person f) where
       showsPrec :: Int -> Person f -> ShowS
    showsPrec Int
    prec Person f
    person String
    rest =
           String
    "Person{" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    separator String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    "name=" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Int -> f String -> ShowS
    forall (f :: * -> *) a. (Show1 f, Show a) => Int -> f a -> ShowS
    showsPrec1 Int
    prec' (Person f -> f String
    forall (f :: * -> *). Person f -> f String
    name Person f
    person)
                (String
    "," String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    separator String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    "age=" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Int -> f Int -> ShowS
    forall (f :: * -> *) a. (Show1 f, Show a) => Int -> f a -> ShowS
    showsPrec1 Int
    prec' (Person f -> f Int
    forall (f :: * -> *). Person f -> f Int
    age Person f
    person)
                (String
    "," String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    separator String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    "mother=" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Int -> f (Maybe PersonVerified) -> ShowS
    forall (f :: * -> *) a. (Show1 f, Show a) => Int -> f a -> ShowS
    showsPrec1 Int
    prec' (Person f -> f (Maybe PersonVerified)
    forall (f :: * -> *). Person f -> f (Maybe PersonVerified)
    mother Person f
    person)
                (String
    "," String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    separator String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    "father=" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Int -> f (Maybe PersonVerified) -> ShowS
    forall (f :: * -> *) a. (Show1 f, Show a) => Int -> f a -> ShowS
    showsPrec1 Int
    prec' (Person f -> f (Maybe PersonVerified)
    forall (f :: * -> *). Person f -> f (Maybe PersonVerified)
    father Person f
    person)
                (String
    "}" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    rest))))
            where prec' :: Int
    prec' = Int -> Int
    forall a. Enum a => a -> a
    succ Int
    prec
                  separator :: String
    separator = String
    "\n" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ Int -> Char -> String
    forall a. Int -> a -> [a]
    replicate Int
    prec' Char
    ' '
    ~~~

    You can create the rank-2 class instances for your data types manually, or you can generate the instances using the
    templates imported from the `Rank2.TH` module with a single line of code per data type:

    ~~~ {.haskell}
    $(Rank2.TH.deriveAll ''Person)
    ~~~

    Either way, once you have the rank-2 type class instances, you can use them to easily convert between records with
    different parameters `f`.

    ### Record construction and modification examples ###

    In case of our `Person` record, a couple of helper functions will prove handy:

    ~~~ {.haskell}
    findPerson :: PersonDatabase -> String -> Maybe PersonVerified
    findPerson :: PersonDatabase -> String -> Maybe PersonVerified
    findPerson PersonDatabase
    db String
    nameToFind = (PersonVerified -> Bool) -> PersonDatabase -> Maybe PersonVerified
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
    find ((String
    nameToFind String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    ==) (String -> Bool)
    -> (PersonVerified -> String) -> PersonVerified -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Identity String -> String
    forall a. Identity a -> a
    runIdentity (Identity String -> String)
    -> (PersonVerified -> Identity String) -> PersonVerified -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . PersonVerified -> Identity String
    forall (f :: * -> *). Person f -> f String
    name) PersonDatabase
    db

    personByName :: PersonDatabase -> String -> Either String (Maybe PersonVerified)
    personByName :: PersonDatabase -> String -> Either String (Maybe PersonVerified)
    personByName PersonDatabase
    db String
    personName
       | String -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null String
    personName = Maybe PersonVerified -> Either String (Maybe PersonVerified)
    forall a b. b -> Either a b
    Right Maybe PersonVerified
    forall a. Maybe a
    Nothing
       | p :: Maybe PersonVerified
    p@Just{} <- PersonDatabase -> String -> Maybe PersonVerified
    findPerson PersonDatabase
    db String
    personName = Maybe PersonVerified -> Either String (Maybe PersonVerified)
    forall a b. b -> Either a b
    Right Maybe PersonVerified
    p
       | Bool
    otherwise = String -> Either String (Maybe PersonVerified)
    forall a b. a -> Either a b
    Left (String
    "Nobody by name of " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    personName)
    ~~~

    Now we can start by constructing a `Person` record with rank-2 functions for fields. This record is not so much a person
    as a field-by-field person verifier:

    ~~~ {.haskell}
    personChecker :: PersonDatabase -> Person (Const String Rank2.~> Either String)
    personChecker :: PersonDatabase -> Person (Const String ~> Either String)
    personChecker PersonDatabase
    db =
       Person{name :: Arrow (Const String) (Either String) String
    name= (Const String String -> Either String String)
    -> Arrow (Const String) (Either String) String
    forall {k} (p :: k -> *) (q :: k -> *) (a :: k).
    (p a -> q a) -> Arrow p q a
    Rank2.Arrow (String -> Either String String
    forall a b. b -> Either a b
    Right (String -> Either String String)
    -> (Const String String -> String)
    -> Const String String
    -> Either String String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Const String String -> String
    forall {k} a (b :: k). Const a b -> a
    getConst),
              age :: Arrow (Const String) (Either String) Int
    age= (Const String Int -> Either String Int)
    -> Arrow (Const String) (Either String) Int
    forall {k} (p :: k -> *) (q :: k -> *) (a :: k).
    (p a -> q a) -> Arrow p q a
    Rank2.Arrow ((Const String Int -> Either String Int)
     -> Arrow (Const String) (Either String) Int)
    -> (Const String Int -> Either String Int)
    -> Arrow (Const String) (Either String) Int
    forall a b. (a -> b) -> a -> b
    $ \(Const String
    age)->
                   case ReadS Int
    forall a. Read a => ReadS a
    reads String
    age
                   of [(Int
    n, String
    "")] -> Int -> Either String Int
    forall a b. b -> Either a b
    Right Int
    n
                      [(Int, String)]
    _ -> String -> Either String Int
    forall a b. a -> Either a b
    Left (String
    age String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    " is not an integer"),
              mother :: Arrow (Const String) (Either String) (Maybe PersonVerified)
    mother= (Const String (Maybe PersonVerified)
     -> Either String (Maybe PersonVerified))
    -> Arrow (Const String) (Either String) (Maybe PersonVerified)
    forall {k} (p :: k -> *) (q :: k -> *) (a :: k).
    (p a -> q a) -> Arrow p q a
    Rank2.Arrow (PersonDatabase -> String -> Either String (Maybe PersonVerified)
    personByName PersonDatabase
    db (String -> Either String (Maybe PersonVerified))
    -> (Const String (Maybe PersonVerified) -> String)
    -> Const String (Maybe PersonVerified)
    -> Either String (Maybe PersonVerified)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Const String (Maybe PersonVerified) -> String
    forall {k} a (b :: k). Const a b -> a
    getConst),
              father :: Arrow (Const String) (Either String) (Maybe PersonVerified)
    father= (Const String (Maybe PersonVerified)
     -> Either String (Maybe PersonVerified))
    -> Arrow (Const String) (Either String) (Maybe PersonVerified)
    forall {k} (p :: k -> *) (q :: k -> *) (a :: k).
    (p a -> q a) -> Arrow p q a
    Rank2.Arrow (PersonDatabase -> String -> Either String (Maybe PersonVerified)
    personByName PersonDatabase
    db (String -> Either String (Maybe PersonVerified))
    -> (Const String (Maybe PersonVerified) -> String)
    -> Const String (Maybe PersonVerified)
    -> Either String (Maybe PersonVerified)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Const String (Maybe PersonVerified) -> String
    forall {k} a (b :: k). Const a b -> a
    getConst)}
    ~~~

    We can apply it using the [Rank2.<*>](http://hackage.haskell.org/package/rank2classes/docs/Rank2.html#v:-60--42--62-)
    method of the [Rank2.Apply](http://hackage.haskell.org/package/rank2classes/docs/Rank2.html#t:Apply) type class to a bunch
    of textual fields for `Person`, and get back either errors or proper field values:

    ~~~ {.haskell}
    verify :: PersonDatabase -> PersonText -> PersonWithErrors
    verify :: PersonDatabase -> PersonText -> PersonWithErrors
    verify PersonDatabase
    db PersonText
    person = PersonDatabase -> Person (Const String ~> Either String)
    personChecker PersonDatabase
    db Person (Const String ~> Either String)
    -> PersonText -> PersonWithErrors
    forall {k} (g :: (k -> *) -> *) (p :: k -> *) (q :: k -> *).
    Apply g =>
    g (p ~> q) -> g p -> g q
    forall (p :: * -> *) (q :: * -> *).
    Person (p ~> q) -> Person p -> Person q
    Rank2.<*> PersonText
    person
    ~~~

    If there are no errors, we can get a fully verified record by applying
    [Rank2.traverse](http://hackage.haskell.org/package/rank2classes/docs/Rank2.html#v:traverse) to the result:

    ~~~ {.haskell}
    completeVerified :: PersonWithErrors -> Either String PersonVerified
    completeVerified :: PersonWithErrors -> Either String PersonVerified
    completeVerified = (forall a. Either String a -> Either String (Identity a))
    -> PersonWithErrors -> Either String PersonVerified
    forall {k} (g :: (k -> *) -> *) (m :: * -> *) (p :: k -> *)
           (q :: k -> *).
    (Traversable g, Applicative m) =>
    (forall (a :: k). p a -> m (q a)) -> g p -> m (g q)
    forall (m :: * -> *) (p :: * -> *) (q :: * -> *).
    Applicative m =>
    (forall a. p a -> m (q a)) -> Person p -> m (Person q)
    Rank2.traverse (a -> Identity a
    forall a. a -> Identity a
    Identity (a -> Identity a) -> Either String a -> Either String (Identity a)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$>)
    ~~~

    or we can go in the opposite direction with
    [Rank2.<$>](http://hackage.haskell.org/package/rank2classes/docs/Rank2.html#v:-60--36--62-):

    ~~~ {.haskell}
    uncompleteVerified :: PersonVerified -> PersonWithErrors
    uncompleteVerified :: PersonVerified -> PersonWithErrors
    uncompleteVerified = (forall a. Identity a -> Either String a)
    -> PersonVerified -> PersonWithErrors
    forall {k} (g :: (k -> *) -> *) (p :: k -> *) (q :: k -> *).
    Functor g =>
    (forall (a :: k). p a -> q a) -> g p -> g q
    Rank2.fmap (a -> Either String a
    forall a b. b -> Either a b
    Right (a -> Either String a)
    -> (Identity a -> a) -> Identity a -> Either String a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Identity a -> a
    forall a. Identity a -> a
    runIdentity)
    ~~~

    If on the other hand there *are* errors, we can collect them using
    [Rank2.foldMap](http://hackage.haskell.org/package/rank2classes/docs/Rank2.html#v:foldMap):

    ~~~ {.haskell}
    verificationErrors :: PersonWithErrors -> [String]
    verificationErrors :: PersonWithErrors -> [String]
    verificationErrors = (forall a. Either String a -> [String])
    -> PersonWithErrors -> [String]
    forall m (p :: * -> *).
    Monoid m =>
    (forall a. p a -> m) -> Person p -> m
    forall {k} (g :: (k -> *) -> *) m (p :: k -> *).
    (Foldable g, Monoid m) =>
    (forall (a :: k). p a -> m) -> g p -> m
    Rank2.foldMap ((String -> [String])
    -> (a -> [String]) -> Either String a -> [String]
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :[]) ([String] -> a -> [String]
    forall a b. a -> b -> a
    const []))
    ~~~

    Here is an example GHCi session:

    ~~~ {.haskell}
    -- |
    -- >>> :{
    --let Right alice = completeVerified $
    --                  verify [] Person{name= Const "Alice", age= Const "44",
    --                                   mother= Const "", father= Const ""}
    --    Right bob = completeVerified $
    --                verify [] Person{name= Const "Bob", age= Const "45",
    --                                 mother= Const "", father= Const ""}
    --    Right charlie = completeVerified $
    --                    verify [alice, bob] Person{name= Const "Charlie", age= Const "19",
    --                                               mother= Const "Alice", father= Const "Bob"}
    -- :}
    --
    -- >>> charlie
    -- Person{
    --  name=Identity "Charlie",
    --  age=Identity 19,
    --  mother=Identity (Just Person{
    --             name=(Identity "Alice"),
    --             age=(Identity 44),
    --             mother=(Identity Nothing),
    --             father=(Identity Nothing)}),
    --  father=Identity (Just Person{
    --             name=(Identity "Bob"),
    --             age=(Identity 45),
    --             mother=(Identity Nothing),
    --             father=(Identity Nothing)})}
    -- >>> :{
    --let dave = verify [alice, bob, charlie]
    --           Person{name= Const "Dave", age= Const "young",
    --                  mother= Const "Lise", father= Const "Mike"}
    -- :}
    --
    -- >>> dave
    -- Person{
    --  name=Right "Dave",
    --  age=Left "young is not an integer",
    --  mother=Left "Nobody by name of Lise",
    --  father=Left "Nobody by name of Mike"}
    -- >>> completeVerified dave
    -- Left "young is not an integer"
    -- >>> verificationErrors  dave
    -- ["young is not an integer","Nobody by name of Lise","Nobody by name of Mike"]
    -- >>> Rank2.distribute [alice, bob, charlie]
    -- Person{
    --  name=Compose [Identity "Alice",Identity "Bob",Identity "Charlie"],
    --  age=Compose [Identity 44,Identity 45,Identity 19],
    --  mother=Compose [Identity Nothing,Identity Nothing,Identity (Just Person{
    --             name=(Identity "Alice"),
    --             age=(Identity 44),
    --             mother=(Identity Nothing),
    --             father=(Identity Nothing)})],
    --  father=Compose [Identity Nothing,Identity Nothing,Identity (Just Person{
    --             name=(Identity "Bob"),
    --             age=(Identity 45),
    --             mother=(Identity Nothing),
    --             father=(Identity Nothing)})]}
    ~~~

    ### Related works ###

    This package is one of several implementations of a pattern that is often called *Higher-Kinded Data*. Other examples
    include [hkd-lens](https://hackage.haskell.org/package/hkd-lens),
    [barbies](https://hackage.haskell.org/package/barbies), and [higgledy](https://hackage.haskell.org/package/higgledy).

    Grammars are another use case that is almost, but not quite, entirely unlike database records. See
    [grammatical-parsers](https://github.com/blamario/grampa/tree/master/grammatical-parsers) or
    [construct](https://hackage.haskell.org/package/construct) for examples.

    Both database records and grammars are flat structures. If your use case involves trees of rank-2 records, this
    package will probably not suffice. Consider using
    [deep-transformations](https://hackage.haskell.org/package/deep-transformations) instead.