{-# LANGUAGE TypeOperators, LiberalTypeSynonyms, RankNTypes,
             ConstraintKinds, KindSignatures #-}

-- | A collection of type-level operators.
module Control.Type.Operator
    where


import GHC.Prim (Constraint)


-- | A tightly binding version of @->@ that lets you strip parentheses from
-- first-class type-functions. Example:
--
-- >>> f :: Maybe Int ^> String
-- f :: Maybe (Int -> Int)
type (^>) = (->)
infixr 5 ^>

-- | A flipped '^>'.
--
-- >>> f :: Maybe String <^ Int
--
-- Note: this is not partially applied like '^>' and @->@.
type (<^) a b = (^>) b a

-- | Infix application.
--
-- >>> f :: Either String $ Maybe Int
-- f :: Either String (Maybe Int)
type f $ a = f a
infixr 2 $

-- | A flipped '$'.
--
-- >>> f :: Maybe Int & Maybe
-- f :: Maybe (Maybe Int)
type a & f = f a
infixl 1 &

-- | Infix application that takes a two arguments rather than just one.
--
-- >>> f :: Either $$ Int ^> Int $ Int
-- f :: Either (Int -> Int) Int
type (f $$ a) b = f a b
infixr 3 $$

-- | Syntactic sugar for type constraints, allowing omission of repeat
-- type variables.
--
-- >>> a :: (Num % Show) a => a -> String
-- a :: (Num a, Show a) => a -> String
type (%) (c1 :: * -> Constraint) (c2 :: * -> Constraint) a = (c1 a, c2 a)
infixr 2 %