music-score-1.7.2: src/Data/Functor/Couple.hs
{-# LANGUAGE CPP,
GeneralizedNewtypeDeriving,
DeriveDataTypeable,
DeriveFunctor,
DeriveTraversable,
DeriveFoldable,
MultiParamTypeClasses,
TypeFamilies
#-}
-- |
-- Defines two variants of @(,)@ with lifted instances for the standard type classes.
--
-- The 'Functor', 'Applicative' and 'Comonad' instances are the standard instances. The
-- 'Monad' instances are not in base (but should argubly be there). All of these instances
-- are equivalent to 'Writer' in transformers.
--
-- 'Applicative' is used to lift 'Monoid' and the standard numeric classes.
--
-- The only difference between 'Twain' and 'Couple' is the handling of 'Eq' and 'Ord':
-- 'Twain' compares only the second value, while 'Couple' compares both. Thus 'Couple' needs
-- an extra @Ord b@ constraint for all sub-classes of 'Ord'.
--
module Data.Functor.Couple (Twain(..), Couple(..)) where
import Data.Bifunctor
import Data.Functor.Product
import Data.Functor.Identity
import Data.Foldable
import Data.Traversable
import Data.Functor.Adjunction (unzipR)
import Data.Semigroup
import Data.Typeable
import Control.Applicative
import Control.Comonad
import Data.PairMonad ()
import Control.Lens (Wrapped(..), Rewrapped(..), iso)
-- |
-- A variant of pair/writer with lifted instances for the numeric classes, using 'Applicative'.
--
newtype Twain b a = Twain { getTwain :: (b, a) }
deriving (Show, Functor, Traversable, Foldable, Typeable, Applicative, Monad, Comonad, Semigroup, Monoid)
instance Wrapped (Twain b a) where
type Unwrapped (Twain b a) = (b, a)
_Wrapped' = iso getTwain Twain
instance Rewrapped (Twain c a) (Twain c b)
instance (Monoid b, Num a) => Num (Twain b a) where
(+) = liftA2 (+)
(*) = liftA2 (*)
(-) = liftA2 (-)
abs = fmap abs
signum = fmap signum
fromInteger = pure . fromInteger
instance (Monoid b, Fractional a) => Fractional (Twain b a) where
recip = fmap recip
fromRational = pure . fromRational
instance (Monoid b, Floating a) => Floating (Twain b a) where
pi = pure pi
sqrt = fmap sqrt
exp = fmap exp
log = fmap log
sin = fmap sin
cos = fmap cos
asin = fmap asin
atan = fmap atan
acos = fmap acos
sinh = fmap sinh
cosh = fmap cosh
asinh = fmap asinh
atanh = fmap atanh
acosh = fmap acos
instance (Monoid b, Enum a) => Enum (Twain b a) where
toEnum = pure . toEnum
fromEnum = fromEnum . extract
instance (Monoid b, Bounded a) => Bounded (Twain b a) where
minBound = pure minBound
maxBound = pure maxBound
--
-- Eq, Ord and their subclasses
--
-- If comparison takes both values into account, we must add and (Ord b)
-- constraint to all of the following instances. Instead, follow the
-- spirit of the Num et al instances to compare just the second argument.
--
instance Eq a => Eq (Twain b a) where
Twain (b,a) == Twain (b',a') = a == a'
instance Ord a => Ord (Twain b a) where
Twain (b,a) < Twain (b',a') = a < a'
instance (Monoid b, Real a, Enum a, Integral a) => Integral (Twain b a) where
quot = liftA2 quot
rem = liftA2 rem
quotRem = fmap (fmap unzipR) (liftA2 quotRem)
toInteger = toInteger . extract
instance (Monoid b, Real a) => Real (Twain b a) where
toRational = toRational . extract
instance (Monoid b, RealFrac a) => RealFrac (Twain b a) where
properFraction = first extract . unzipR . fmap properFraction
-- |
-- A variant of pair/writer with lifted instances for the numeric classes, using 'Applicative'.
--
newtype Couple b a = Couple { getCouple :: (b, a) }
deriving (Show, Functor, Foldable, Traversable, Typeable, Applicative, Monad, Comonad, Semigroup, Monoid)
instance Wrapped (Couple b a) where
type Unwrapped (Couple b a) = (b, a)
_Wrapped' = iso getCouple Couple
instance Rewrapped (Couple c a) (Couple c b)
instance (Monoid b, Num a) => Num (Couple b a) where
(+) = liftA2 (+)
(*) = liftA2 (*)
(-) = liftA2 (-)
abs = fmap abs
signum = fmap signum
fromInteger = pure . fromInteger
instance (Monoid b, Fractional a) => Fractional (Couple b a) where
recip = fmap recip
fromRational = pure . fromRational
instance (Monoid b, Floating a) => Floating (Couple b a) where
pi = pure pi
sqrt = fmap sqrt
exp = fmap exp
log = fmap log
sin = fmap sin
cos = fmap cos
asin = fmap asin
atan = fmap atan
acos = fmap acos
sinh = fmap sinh
cosh = fmap cosh
asinh = fmap asinh
atanh = fmap atanh
acosh = fmap acos
instance (Monoid b, Enum a) => Enum (Couple b a) where
toEnum = pure . toEnum
fromEnum = fromEnum . extract
instance (Monoid b, Bounded a) => Bounded (Couple b a) where
minBound = pure minBound
maxBound = pure maxBound
instance (Eq b, Eq a) => Eq (Couple b a) where
Couple ((b,a)) == Couple (b',a') = (b,a) == (b',a')
instance (Ord b, Ord a) => Ord (Couple b a) where
Couple (b,a) < Couple (b',a') = (b,a) < (b',a')
instance (Monoid b, Ord b, Real a, Enum a, Integral a) => Integral (Couple b a) where
quot = liftA2 quot
rem = liftA2 rem
quotRem = fmap (fmap unzipR) (liftA2 quotRem)
toInteger = toInteger . extract
instance (Monoid b, Ord b, Real a) => Real (Couple b a) where
toRational = toRational . extract
instance (Monoid b, Ord b, RealFrac a) => RealFrac (Couple b a) where
properFraction = first extract . unzipR . fmap properFraction