| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Type.Cluss
Contents
- class In as a where
- data Type a
- data a <| p
- type Unary a p = a <| p
- type Binary a p = a <| p
- type Ternary a p = a <| p
- type Quaternary a p = a <| p
- type Quinary a p = a <| p
- type Senary a p = a <| p
- type AllOf as = AllOf' as as
- data family AllOf' ts as f
- class (True ~ False) => This a
- class Pure a
- type Is a b = a ~ b
- class (p a, q a) => (p >+< q) a
- class (p a b, q a b) => (p >++< q) a b
- class (p a b c, q a b c) => (p >+++< q) a b c
- class (p a b c d, q a b c d) => (p >++++< q) a b c d
- class (p a b c d e, q a b c d e) => (p >+++++< q) a b c d e
- class (p a b c d e f, q a b c d e f) => (p >++++++< q) a b c d e f
- class (p a, q b) => (p >|< q) a b
- class (p a b, q c) => (p >||< q) a b c
- class (p a b c, q d) => (p >|||< q) a b c d
- class (p a b c d, q e) => (p >||||< q) a b c d e
- class (p a b c d e, q f) => (p >|||||< q) a b c d e f
- type AllOfI as = AllOfI' as as
- type AllOfI' ts as = AllOf' ts as Id
- andI :: a -> AllOfI' ts as -> AllOfI' ts (Type a : as)
- andI1 :: (forall b. Modify (In ts) p b => a b) -> AllOfI' ts as -> AllOfI' ts ((a <| p) : as)
- andI2 :: (forall b c. Modify2 (In ts) p b c => a b c) -> AllOfI' ts as -> AllOfI' ts ((a <| p) : as)
- andI3 :: (forall b c d. Modify3 (In ts) p b c d => a b c d) -> AllOfI' ts as -> AllOfI' ts ((a <| p) : as)
- andI4 :: (forall b c d e. Modify4 (In ts) p b c d e => a b c d e) -> AllOfI' ts as -> AllOfI' ts ((a <| p) : as)
- andI5 :: (forall b c d e f. Modify5 (In ts) p b c d e f => a b c d e f) -> AllOfI' ts as -> AllOfI' ts ((a <| p) : as)
- andI6 :: (forall b c d e f g. Modify6 (In ts) p b c d e f g => a b c d e f g) -> AllOfI' ts as -> AllOfI' ts ((a <| p) : as)
- noneI :: AllOfI' ts []
- projI :: In as a => AllOfI as -> a
- type AllOfF as t = AllOfF' as as t
- type AllOfF' ts as t = AllOf' ts as (Func t)
- andF :: (a -> t) -> AllOfF' ts as t -> AllOfF' ts (Type a : as) t
- andF1 :: (forall b. Modify (In ts) p b => a b -> t) -> AllOfF' ts as t -> AllOfF' ts ((a <| p) : as) t
- andF2 :: (forall b c. Modify2 (In ts) p b c => a b c -> t) -> AllOfF' ts as t -> AllOfF' ts ((a <| p) : as) t
- andF3 :: (forall b c d. Modify3 (In ts) p b c d => a b c d -> t) -> AllOfF' ts as t -> AllOfF' ts ((a <| p) : as) t
- andF4 :: (forall b c d e. Modify4 (In ts) p b c d e => a b c d e -> t) -> AllOfF' ts as t -> AllOfF' ts ((a <| p) : as) t
- andF5 :: (forall b c d e f. Modify5 (In ts) p b c d e f => a b c d e f -> t) -> AllOfF' ts as t -> AllOfF' ts ((a <| p) : as) t
- andF6 :: (forall b c d e f g. Modify6 (In ts) p b c d e f g => a b c d e f g -> t) -> AllOfF' ts as t -> AllOfF' ts ((a <| p) : as) t
- noneF :: AllOfF' ts [] t
- projF :: In as a => AllOfF as t -> a -> t
Clusses
is a cluss, where In asas is a list of type patterns.
Normally, as is concrete and does not contain any type variables, like In [Binary (->) (Show >|< This), Type String] a.
When a satisfies In as a, you can use the method .
proj :: AllOf as f -> f a
Clusses call for some language extensions. Basically, this language pragma will do.
{-# LANGUAGE DataKinds, FlexibleContexts, TypeOperators #-}
Internally, "type pattern matching" is executed by Where, a closed type family, which cannot check if a type satisfies a constraint.
If as has many type patterns that can match a, only the first one matches a.
Instances
| In' k (Where k as a) as as a => In k as a |
Type Patterns
Type patterns are used in the type list (first parameter) of In.
Each type pattern corresponds to the head of an instance declaration for a type class, namely, instance ... where.
The empty type Type a is a type pattern.
For example, the type pattern Type Int corresponds to instance C Int where ... (C is a type class).
Note that the type variable a can be of any kind.
The empty type a <| p is a type pattern,
where a is a type constructor, and p is a constraint function for the type variables for the constructor a.
For example, the type pattern [] <| Show corresponds to instance (Show a) => C [a] where ... (C is a type class).
You can replace any of Unary, Binary, ..., Senary with <|,
but you can sometimes save the effort of annotating kinds
using Unary, Binary, ..., Senary instead of <|,
especially when using PolyKinds extension,
because kinds of parameters are restricted in Unary, Binary, ..., Senary.
Instances
| data AllOf' k ts ((:) * (Senary k1 k2 k3 k4 k5 k6 k a p) as) = And6 (forall b c d e f' g. Modify6 k k k k k k (In k ts) p b c d e f' g => f (a b c d e f' g)) (AllOf' k ts as f) | |
| data AllOf' k ts ((:) * (Quinary k1 k2 k3 k4 k5 k a p) as) = And5 (forall b c d e f'. Modify5 k k k k k (In k ts) p b c d e f' => f (a b c d e f')) (AllOf' k ts as f) | |
| data AllOf' k ts ((:) * (Quaternary k1 k2 k3 k4 k a p) as) = And4 (forall b c d e. Modify4 k k k k (In k ts) p b c d e => f (a b c d e)) (AllOf' k ts as f) | |
| data AllOf' k ts ((:) * (Ternary k1 k2 (k3 -> k) k3 a p) as) = And3 (forall b c d. Modify3 k k k (In k ts) p b c d => f (a b c d)) (AllOf' k ts as f) | |
| data AllOf' k ts ((:) * (Binary k1 k2 k a p) as) = And2 (forall b c. Modify2 k k (In k ts) p b c => f (a b c)) (AllOf' k ts as f) | |
| data AllOf' k ts ((:) * (Unary k1 k a p) as) = And1 (forall b. Modify k (In k ts) p b => f (a b)) (AllOf' k ts as f) |
type Unary a p = a <| p Source
a , with <| pa being of the kind i -> k and p, i -> .
Constraint
type Binary a p = a <| p Source
a , with <| pa being of the kind i -> i' -> k and p, i -> i' -> .
Constraint
type Ternary a p = a <| p Source
a , with <| pa being of the kind i -> i' -> i'' -> k and p, i -> i' -> i'' -> .
Constraint
type Quaternary a p = a <| p Source
a , with <| pa being of the kind i -> i' -> i'' -> i''' -> k and p, i -> i' -> i'' -> i''' -> .
Constraint
type Quinary a p = a <| p Source
a , with <| pa being of the kind i -> i' -> i'' -> i''' -> i'''' -> k and p, i -> i' -> i'' -> i''' -> i'''' -> .
Constraint
type Senary a p = a <| p Source
a , with <| pa being of the kind i -> i' -> i'' -> i''' -> i'''' -> i''''' -> k and p, i -> i' -> i'' -> i''' -> i'''' -> i''''' -> .
Constraint
Instance Products
type AllOf as = AllOf' as as Source
is a tuple that contains values of the type AllOf as ff a,
where a can be any type that satisfies In as a.
Each value corresponds to each type pattern,
and the values in must be in the same order as the type patterns in AllOf as fas.
And, And1, And2, ..., And6 are used to combine the values
and None must be added at the end.
You have to use And for ,
Type aAnd1 for , Unary a pAnd2 for ,
..., Binary a pAnd6 for .
Senary a p
data family AllOf' ts as f Source
Instances
| data AllOf' k ts ([] *) = None | |
| data AllOf' k ts ((:) * (Senary k1 k2 k3 k4 k5 k6 k a p) as) = And6 (forall b c d e f' g. Modify6 k k k k k k (In k ts) p b c d e f' g => f (a b c d e f' g)) (AllOf' k ts as f) | |
| data AllOf' k ts ((:) * (Quinary k1 k2 k3 k4 k5 k a p) as) = And5 (forall b c d e f'. Modify5 k k k k k (In k ts) p b c d e f' => f (a b c d e f')) (AllOf' k ts as f) | |
| data AllOf' k ts ((:) * (Quaternary k1 k2 k3 k4 k a p) as) = And4 (forall b c d e. Modify4 k k k k (In k ts) p b c d e => f (a b c d e)) (AllOf' k ts as f) | |
| data AllOf' k ts ((:) * (Ternary k1 k2 (k3 -> k) k3 a p) as) = And3 (forall b c d. Modify3 k k k (In k ts) p b c d => f (a b c d)) (AllOf' k ts as f) | |
| data AllOf' k ts ((:) * (Binary k1 k2 k a p) as) = And2 (forall b c. Modify2 k k (In k ts) p b c => f (a b c)) (AllOf' k ts as f) | |
| data AllOf' k ts ((:) * (Unary k1 k a p) as) = And1 (forall b. Modify k (In k ts) p b => f (a b)) (AllOf' k ts as f) | |
| data AllOf' k ts ((:) * (Type k a) as) = And (f a) (AllOf' k ts as f) |
Constraint Combinators
Constraint combinators are used in the second parameter of <|, Unary, Binary, ..., Senary.
Note that each combinator is kind-polymorphic.
Basic Combinators
class (True ~ False) => This a Source
This creates a recursion.
In other words, This will work as itself
when used in the type list (first parameter) In asas of In,
combined with Type, <|, Unary, Binary, ..., Senary,
>+<, >++<, ..., >++++++<,
>|<, >||<, ..., >|||||<.
Note that This won't be expanded into
if the condition described above is not satisfied.
Internally, the expansion is executed by In asModify, Modify2, ..., Modify6.
The instance of This itself can't be created
since the context True~False will never be satisfied.
There is no predetermined limit of recursion depth,
but GHC has a fixed-depth recursion stack for safety,
so you may need to increase the stack depth with -fcontext-stack=N.
Combinators for Overlaying Contraints
class (p a, q a) => (p >+< q) a infixl 9 Source
(p >+< q) a == (p a, q a)
Instances
| (p a, q a) => (>+<) k p q a |
class (p a b, q a b) => (p >++< q) a b infixl 9 Source
(p >++< q) a b == (p a b, q a b)
Instances
| (p a b, q a b) => (>++<) k k p q a b |
class (p a b c, q a b c) => (p >+++< q) a b c infixl 9 Source
(p >+++< q) a b c == (p a b c, q a b c)
Instances
| (p a b c, q a b c) => (>+++<) k k k p q a b c |
class (p a b c d, q a b c d) => (p >++++< q) a b c d infixl 9 Source
(p >++++< q) a b c d == (p a b c d, q a b c d)
Instances
| (p a b c d, q a b c d) => (>++++<) k k k k p q a b c d |
class (p a b c d e, q a b c d e) => (p >+++++< q) a b c d e infixl 9 Source
(p >+++++< q) a b c d e == (p a b c d e, q a b c d e)
Instances
| (p a b c d e, q a b c d e) => (>+++++<) k k k k k p q a b c d e |
class (p a b c d e f, q a b c d e f) => (p >++++++< q) a b c d e f infixl 9 Source
(p >++++++< q) a b c d e f == (p a b c d e f, q a b c d e f)
Instances
| (p a b c d e f, q a b c d e f) => (>++++++<) k k k k k k p q a b c d e f |
Combinators for Bonding Contraints
class (p a, q b) => (p >|< q) a b infixl 8 Source
(p >|< q) a b == (p a, q b)
Instances
| (p a, q b) => (>|<) k k p q a b |
class (p a b, q c) => (p >||< q) a b c infixl 8 Source
(p >||< q) a b c == (p a b, q c)
Instances
| (p a b, q c) => (>||<) k k k p q a b c |
class (p a b c, q d) => (p >|||< q) a b c d infixl 8 Source
(p >|||< q) a b c d == (p a b c, q d)
Instances
| (p a b c, q d) => (>|||<) k k k k p q a b c d |
class (p a b c d, q e) => (p >||||< q) a b c d e infixl 8 Source
(p >||||< q) a b c d e == (p a b c d, q e)
Instances
| (p a b c d, q e) => (>||||<) k k k k k p q a b c d e |
class (p a b c d e, q f) => (p >|||||< q) a b c d e f infixl 8 Source
(p >|||||< q) a b c d e f == (p a b c d e, q f)
Instances
| (p a b c d e, q f) => (>|||||<) k k k k k k p q a b c d e f |
Helpers
Helpers for Identical Constructors
andI1 :: (forall b. Modify (In ts) p b => a b) -> AllOfI' ts as -> AllOfI' ts ((a <| p) : as) infixr 0 Source
andI2 :: (forall b c. Modify2 (In ts) p b c => a b c) -> AllOfI' ts as -> AllOfI' ts ((a <| p) : as) infixr 0 Source
andI3 :: (forall b c d. Modify3 (In ts) p b c d => a b c d) -> AllOfI' ts as -> AllOfI' ts ((a <| p) : as) infixr 0 Source
andI4 :: (forall b c d e. Modify4 (In ts) p b c d e => a b c d e) -> AllOfI' ts as -> AllOfI' ts ((a <| p) : as) infixr 0 Source
andI5 :: (forall b c d e f. Modify5 (In ts) p b c d e f => a b c d e f) -> AllOfI' ts as -> AllOfI' ts ((a <| p) : as) infixr 0 Source
andI6 :: (forall b c d e f g. Modify6 (In ts) p b c d e f g => a b c d e f g) -> AllOfI' ts as -> AllOfI' ts ((a <| p) : as) infixr 0 Source
Helpers for Function Constructors
andF1 :: (forall b. Modify (In ts) p b => a b -> t) -> AllOfF' ts as t -> AllOfF' ts ((a <| p) : as) t infixr 0 Source
andF2 :: (forall b c. Modify2 (In ts) p b c => a b c -> t) -> AllOfF' ts as t -> AllOfF' ts ((a <| p) : as) t infixr 0 Source
andF3 :: (forall b c d. Modify3 (In ts) p b c d => a b c d -> t) -> AllOfF' ts as t -> AllOfF' ts ((a <| p) : as) t infixr 0 Source
andF4 :: (forall b c d e. Modify4 (In ts) p b c d e => a b c d e -> t) -> AllOfF' ts as t -> AllOfF' ts ((a <| p) : as) t infixr 0 Source
andF5 :: (forall b c d e f. Modify5 (In ts) p b c d e f => a b c d e f -> t) -> AllOfF' ts as t -> AllOfF' ts ((a <| p) : as) t infixr 0 Source
andF6 :: (forall b c d e f g. Modify6 (In ts) p b c d e f g => a b c d e f g -> t) -> AllOfF' ts as t -> AllOfF' ts ((a <| p) : as) t infixr 0 Source
Examples
Example1: Hello
Let's begin with a basic example.
type Hellos = [
Type String,
Type Int,
Type Double,
Unary [] Show,
Quaternary (,,,) (This >|< This >||< This >|||< This)]
hello :: In Hellos a => a -> String
hello = projF (
(\s -> "hello, " ++ s) `andF`
(\n -> "Mr. " ++ show n) `andF`
(\x -> show (x / 2) ++ " times two") `andF`
(\xs -> concatMap ((++", ") . show) xs ++ "period") `andF1`
(\(x,y,z,w) ->
hello x ++ " and " ++ hello y ++ " and " ++
hello z ++ " and " ++ hello w) `andF4`
noneF :: AllOfF Hellos String)
main = putStrLn $
hello ("world", 42 :: Int, 3.14 :: Double, [True, False])
This is the result.
hello, world and Mr. 42 and 1.57 times two and True, False, period
Example2: Printf
With a recursive cluss, you can easily make a function that can take a variable number of arguments. The function below is a simplified C-style printf.
type Printfs = [Binary (->) (Show >|< This), Type String]
printf :: In Printfs a => String -> a
printf s = projI (
(\x -> printf (go s (show x))) `andI2`
s `andI`
noneI :: AllOfI Printfs)
where
go ('@' : cs) t = t ++ cs
go (c : cs) t = c : go cs t
go [] t = error "there is no '@' any more!"
main = putStrLn $
printf "@ good @ and @" 12 "men" True
This is the result.
12 good "men" and True
Example3: Monad
Here is a more complex example. When the type of a "cluss method" is complex, you generally have to create newtypes (like Bind and Return below).
type Monads = [Type [], Unary (->) Pure, Unary (,) Monoid, Unary Wrap This]
newtype Wrap m a = Wrap {unWrap :: m a}
newtype Bind a b m = Bind {unBind :: m a -> (a -> m b) -> m b}
newtype Return a m = Return {unReturn :: a -> m a}
bind :: In Monads m => m a -> (a -> m b) -> m b
bind = unBind $ proj (
Bind (\m k -> concatMap k m) `And`
Bind (\m k e -> k (m e) e) `And1`
Bind (\(a,x) k -> let (a',x') = k x in (a<>a',x')) `And1`
Bind (\m k -> Wrap (unWrap m `bind` (unWrap . k))) `And1`
None :: AllOf Monads (Bind a b))
return' :: In Monads m => a -> m a
return' = unReturn $ proj (
Return (: []) `And`
Return const `And1`
Return ((,) mempty) `And1`
Return (Wrap . return') `And1`
None :: AllOf Monads (Return a))
infixl 1 `bind`
main = print $
return' 1 `bind` replicate 3 `bind` (\n -> [n .. n+4])
This is the result.
[1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]