{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE UndecidableInstances #-} -- | -- Module : Numeric.OneLiner -- Description : Derived methods for numeric typeclasses -- Copyright : (c) Justin Le 2018 -- License : BSD-3 -- Maintainer : justin@jle.im -- Stability : unstable -- Portability : portable -- -- Derived methods for numeric typeclasses, using "Generics.OneLiner" and -- "GHC.Generics". -- -- Can be used for any types (deriving 'Generic') made with a single -- constructor, where every field is an instance of 'Num' (or 'Fractional' -- or 'Floating', depending on the function). -- -- Also includes a newtype wrapper that imbues any such data type with an -- instant 'Num' (and 'Fractional' and 'Floating') instance. -- -- See README for details on usage instructions and motivations. -- module Numeric.OneLiner ( -- * Newtype wrapper GNum(..) -- * Generics-derived methods -- $num -- ** Num , gPlus , gMinus , gTimes , gNegate , gAbs , gSignum , gFromInteger -- ** Fractional , gDivide , gRecip , gFromRational -- ** Floating , gPi , gExp , gLog , gSqrt , gPower , gLogBase , gSin , gCos , gTan , gAsin , gAcos , gAtan , gSinh , gCosh , gTanh , gAsinh , gAcosh , gAtanh ) where import Data.Data import GHC.Generics import Generics.OneLiner -- | If @a@ is a data type with a single constructor whose fields are all -- instances of 'Num', then @'GNum' a@ has a 'Num' instance. -- -- If @a@ is a data type with a single constructor whose fields are all -- instances of 'Fractional', then @'GNum' a@ has a 'Fractional' instance. -- -- If @a@ is a data type with a single constructor whose fields are all -- instances of 'Floating', then @'GNum' a@ has a 'Floating' instance. -- newtype GNum a = GNum { getGNum :: a } deriving (Eq, Ord, Show, Read, Data, Generic, Functor, Foldable, Traversable) instance (ADTRecord a, Constraints (GNum a) Num) => Num (GNum a) where (+) = gPlus (-) = gMinus (*) = gTimes negate = gNegate abs = gAbs signum = gSignum fromInteger = gFromInteger instance (ADTRecord a, Constraints (GNum a) Fractional) => Fractional (GNum a) where (/) = gDivide recip = gRecip fromRational = gFromRational instance (ADTRecord a, Constraints (GNum a) Floating) => Floating (GNum a) where pi = gPi exp = gExp log = gLog sqrt = gSqrt (**) = gPower logBase = gLogBase sin = gSin cos = gCos tan = gTan asin = gAsin acos = gAcos atan = gAtan sinh = gSinh cosh = gCosh tanh = gTanh asinh = gAsinh acosh = gAcosh atanh = gAtanh -- $num -- All of these implement the appropriate functions by carrying them over -- every field of the data type gPlus :: forall a. (ADTRecord a, Constraints a Num) => a -> a -> a gPlus = binaryOp @Num (+) gMinus :: forall a. (ADTRecord a, Constraints a Num) => a -> a -> a gMinus = binaryOp @Num (-) gTimes :: forall a. (ADTRecord a, Constraints a Num) => a -> a -> a gTimes = binaryOp @Num (*) gNegate :: forall a. (ADTRecord a, Constraints a Num) => a -> a gNegate = unaryOp @Num negate gAbs :: forall a. (ADTRecord a, Constraints a Num) => a -> a gAbs = unaryOp @Num abs gSignum :: forall a. (ADTRecord a, Constraints a Num) => a -> a gSignum = unaryOp @Num signum gFromInteger :: forall a. (ADTRecord a, Constraints a Num) => Integer -> a gFromInteger x = nullaryOp @Num (fromInteger x) gDivide :: forall a. (ADTRecord a, Constraints a Fractional) => a -> a -> a gDivide = binaryOp @Fractional (/) gRecip :: forall a. (ADTRecord a, Constraints a Fractional) => a -> a gRecip = unaryOp @Fractional recip gFromRational :: forall a. (ADTRecord a, Constraints a Fractional) => Rational -> a gFromRational x = nullaryOp @Fractional (fromRational x) gPi :: forall a. (ADTRecord a, Constraints a Floating) => a gPi = nullaryOp @Floating pi gExp :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gExp = unaryOp @Floating exp gLog :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gLog = unaryOp @Floating log gSqrt :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gSqrt = unaryOp @Floating sqrt gPower :: forall a. (ADTRecord a, Constraints a Floating) => a -> a -> a gPower = binaryOp @Floating (**) gLogBase :: forall a. (ADTRecord a, Constraints a Floating) => a -> a -> a gLogBase = binaryOp @Floating logBase gSin :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gSin = unaryOp @Floating sin gCos :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gCos = unaryOp @Floating cos gTan :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gTan = unaryOp @Floating tan gAsin :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gAsin = unaryOp @Floating asin gAcos :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gAcos = unaryOp @Floating acos gAtan :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gAtan = unaryOp @Floating atan gSinh :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gSinh = unaryOp @Floating sinh gCosh :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gCosh = unaryOp @Floating cosh gTanh :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gTanh = unaryOp @Floating atanh gAsinh :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gAsinh = unaryOp @Floating asinh gAcosh :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gAcosh = unaryOp @Floating acosh gAtanh :: forall a. (ADTRecord a, Constraints a Floating) => a -> a gAtanh = unaryOp @Floating atanh