-- | It is occasionally useful to define generic functions that can -- not only compute their result as an integer, but also as a symbolic -- expression in the form of an AST. -- -- There are some Haskell hacks for this - it is for example not hard -- to define an instance of 'Num' that constructs an AST. However, -- this falls down for some other interesting classes, like -- 'Integral', which requires both the problematic method -- 'fromInteger', and also that the type is an instance of 'Enum'. -- -- We can always just define hobbled instances that call 'error' for -- those methods that are impractical, but this is ugly. -- -- Hence, this module defines similes to standard Haskell numeric -- typeclasses that have been modified to make generic functions -- slightly easier to write. module Futhark.Util.IntegralExp ( IntegralExp (..) , Wrapped (..) , quotRoundingUp ) where import Data.Int class Num e => IntegralExp e where quot :: e -> e -> e rem :: e -> e -> e div :: e -> e -> e mod :: e -> e -> e sgn :: e -> Maybe Int fromInt8 :: Int8 -> e fromInt16 :: Int16 -> e fromInt32 :: Int32 -> e fromInt64 :: Int64 -> e -- | This wrapper allows you to use a type that is an instance of the -- true class whenever the simile class is required. newtype Wrapped a = Wrapped { wrappedValue :: a } deriving (Eq, Ord, Show) liftOp :: (a -> a) -> Wrapped a -> Wrapped a liftOp op (Wrapped x) = Wrapped $ op x liftOp2 :: (a -> a -> a) -> Wrapped a -> Wrapped a -> Wrapped a liftOp2 op (Wrapped x) (Wrapped y) = Wrapped $ x `op` y instance Num a => Num (Wrapped a) where (+) = liftOp2 (Prelude.+) (-) = liftOp2 (Prelude.-) (*) = liftOp2 (Prelude.*) abs = liftOp Prelude.abs signum = liftOp Prelude.signum fromInteger = Wrapped . Prelude.fromInteger negate = liftOp Prelude.negate instance Integral a => IntegralExp (Wrapped a) where quot = liftOp2 Prelude.quot rem = liftOp2 Prelude.rem div = liftOp2 Prelude.div mod = liftOp2 Prelude.mod sgn = Just . fromIntegral . signum . toInteger . wrappedValue fromInt8 = fromInteger . toInteger fromInt16 = fromInteger . toInteger fromInt32 = fromInteger . toInteger fromInt64 = fromInteger . toInteger -- | Like 'quot', but rounds up. quotRoundingUp :: IntegralExp num => num -> num -> num quotRoundingUp x y = (x + y - 1) `Futhark.Util.IntegralExp.quot` y