{----------------------------------------------------------------------- Meta-Module : ApplicativeNumeric-inc Copyright : (c) Conal Elliott 2008 License : GPL-3 Maintainer : conal@conal.net Stability : experimental Instances of Num classes for applicative functors. To be #include'd after defining APPLICATIVE as the applicative functor name and CONSTRAINTS as a list of constraints, which must carry its own trailing comma if non-empty. The APPLICATIVE symbol gets #undef'd at the end of this include file, so that multiple includes are convenient. For instance, -- Generate Ord & Enum, but not Eq & Show #define INSTANCE_Ord #define INSTANCE_Enum #define APPLICATIVE Vec2 #include "ApplicativeNumeric-inc.hs" #define APPLICATIVE Vec3 #include "ApplicativeNumeric-inc.hs" #define APPLICATIVE Vec4 #include "ApplicativeNumeric-inc.hs" You'll also have to import 'pure' and 'liftA2' from "Control.Applicative" and specify the FlexibleContexts language extension (due to a hack below). Some instances are generated only if a corresponding CPP symbol is defined: + INSTANCE_Eq + INSTANCE_Ord + INSTANCE_Show + INSTANCE_Enum -----------------------------------------------------------------------} #ifndef CONSTRAINTS #define CONSTRAINTS #endif #ifndef noOv_DEFINED noOv :: String -> a noOv meth = error $ meth ++ ": No overloading" #define noOv_DEFINED #endif -- TODO: splice APPLICATIVE into the error message. I don't have the CPP chops. -- Eq & Show are prerequisites for Num, so they have to be provided somehow -- Hack: the Functor [] is a no-op that allows for a ","-terminated CONSTRAINTS -- Requires FlexibleContexts #ifdef INSTANCE_Eq instance (CONSTRAINTS Functor []) => Eq (APPLICATIVE f9ksE) where (==) = noOv "(==)" #endif #ifdef INSTANCE_Ord instance (CONSTRAINTS Ord f9ksE) => Ord (APPLICATIVE f9ksE) where { min = liftA2 min ; max = liftA2 max } #endif #ifdef INSTANCE_Show instance Show (APPLICATIVE f9ksE) where { show = noOv "show" ; showsPrec = noOv "showsPrec" ; showList = noOv "showList" } #endif #ifdef INSTANCE_Enum instance (CONSTRAINTS Enum f9ksE) => Enum (APPLICATIVE f9ksE) where { succ = fmap succ ; pred = fmap pred ; toEnum = pure . toEnum ; fromEnum = noOv "fromEnum" ; enumFrom = noOv "enumFrom" ; enumFromThen = noOv "enumFromThen" ; enumFromTo = noOv "enumFromTo" ; enumFromThenTo = noOv "enumFromThenTo" } #endif instance (CONSTRAINTS Num f9ksE) => Num (APPLICATIVE f9ksE) where negate = fmap negate (+) = liftA2 (+) (*) = liftA2 (*) fromInteger = pure . fromInteger abs = fmap abs signum = fmap signum instance (CONSTRAINTS Num f9ksE, Ord f9ksE) => Real (APPLICATIVE f9ksE) where toRational = noOv "toRational" instance (CONSTRAINTS Integral f9ksE) => Integral (APPLICATIVE f9ksE) where quot = liftA2 quot rem = liftA2 rem div = liftA2 div mod = liftA2 mod toInteger = noOv "toInteger" x `quotRem` y = (x `quot` y, x `rem` y) x `divMod` y = (x `div` y, x `mod` y) instance (CONSTRAINTS Fractional f9ksE) => Fractional (APPLICATIVE f9ksE) where recip = fmap recip fromRational = pure . fromRational instance (CONSTRAINTS Floating f9ksE) => Floating (APPLICATIVE f9ksE) 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 acosh instance (CONSTRAINTS RealFrac f9ksE) => RealFrac (APPLICATIVE f9ksE) where properFraction = noOv "properFraction" truncate = noOv "truncate" round = noOv "round" ceiling = noOv "ceiling" floor = noOv "floor" instance (CONSTRAINTS RealFloat f9ksE) => RealFloat (APPLICATIVE f9ksE) where floatRadix = noOv "floatRadix" floatDigits = noOv "floatDigits" floatRange = noOv "floatRange" decodeFloat = noOv "decodeFloat" encodeFloat = ((.).(.)) pure encodeFloat exponent = noOv "exponent" significand = noOv "significand" scaleFloat n = fmap (scaleFloat n) isNaN = noOv "isNaN" isInfinite = noOv "isInfinite" isDenormalized = noOv "isDenormalized" isNegativeZero = noOv "isNegativeZero" isIEEE = noOv "isIEEE" atan2 = liftA2 atan2 #undef APPLICATIVE