packages feed

sylvia-0.2.2: Sylvia/Render/Pair.hs

-- |
-- Module      : Sylvia.Render.Pair
-- Copyright   : GPLv3
--
-- Maintainer  : chrisyco@gmail.com
-- Portability : portable
--
-- Strict pairs, and operations on them.

module Sylvia.Render.Pair
    (
    -- * Building and dismantling pairs
      P(..)
    , fstP
    , sndP

    -- * Fancy type aliases
    , PInt
    , PDouble

    -- * Operations on pairs
    , (|+|)
    , (|*|)
    , negateP
    , fromIntegralP
    ) where

import Control.Applicative
import Control.Comonad.Trans.Store
import Data.Lens.Common

-- | A strict pair.
data P a = !a :| !a
    deriving (Eq, Ord, Bounded, Read, Show)

infix 5 :|

instance Functor P where
    fmap f (x :| y) = f x :| f y

instance Applicative P where
    pure x = x :| x
    f :| g <*> x :| y = f x :| g y

-- | A pair of integers.
type PInt = P Int

-- | A pair of doubles.
type PDouble = P Double

-- | Add or multiply the corresponding values in two pairs.
(|+|), (|*|) :: Num a => P a -> P a -> P a
(|+|) = liftA2 (+)
(|*|) = liftA2 (*)

infixl 6 |+|
infixl 7 |*|

-- | Negate the contents of a pair.
negateP :: Num a => P a -> P a
negateP = fmap negate

-- | Apply 'fromIntegral' to the contents of a pair.
fromIntegralP :: (Integral a, Num b) => P a -> P b
fromIntegralP = fmap fromIntegral

-- | Lens on the first element.
fstP :: Lens (P a) a
fstP = Lens $ \(x :| y) -> store (\x' -> x' :| y) x

-- | Lens on the second element.
sndP :: Lens (P a) a
sndP = Lens $ \(x :| y) -> store (\y' -> x :| y') y