Skip to content

Commit

Permalink
Rename div and mod to quot and rem and introduce proper div and mod (#…
Browse files Browse the repository at this point in the history
…155)

The functions in `Rel8.Expr.Num` that were called `div` and `mod` actually behaved like the Haskell functions `quot` and `rem` on negative values.
  • Loading branch information
shane-circuithub committed Jan 26, 2022
1 parent 2a25126 commit 2833c4b
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 7 deletions.
1 change: 1 addition & 0 deletions src/Rel8.hs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ module Rel8
-- ** @null@
, NotNull
, Nullable
, Homonullable
, null
, nullify
, nullable
Expand Down
45 changes: 39 additions & 6 deletions src/Rel8/Expr/Num.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,24 @@
{-# options_ghc -fno-warn-redundant-constraints #-}

module Rel8.Expr.Num
( fromIntegral, realToFrac, div, mod, ceiling, floor, round, truncate
( fromIntegral
, realToFrac
, div, mod, divMod
, quot, rem, quotRem
, ceiling, floor, round, truncate
)
where

-- base
import Prelude ()
import Prelude ( (+), (-), fst, negate, signum, snd )

-- rel
import Rel8.Expr ( Expr( Expr ) )
import Rel8.Expr.Eq ( (==.) )
import Rel8.Expr.Function ( function )
import Rel8.Expr.Opaleye ( castExpr )
import Rel8.Schema.Null ( Homonullable, Sql )
import Rel8.Table.Bool ( bool )
import Rel8.Type.Num ( DBFractional, DBIntegral, DBNum )


Expand All @@ -42,14 +48,41 @@ ceiling :: (Sql DBFractional a, Sql DBIntegral b, Homonullable a b)
ceiling = function "ceiling"


-- | Perform integral division. Corresponds to the @div()@ function.
-- | Emulates the behaviour of the Haskell function 'Prelude.div' in
-- PostgreSQL.
div :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
div = function "div"
div n d = fst (divMod n d)


-- | Corresponds to the @mod()@ function.
-- | Emulates the behaviour of the Haskell function 'Prelude.mod' in
-- PostgreSQL.
mod :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
mod = function "mod"
mod n d = snd (divMod n d)


-- | Simultaneous 'div' and 'mod'.
divMod :: Sql DBIntegral a => Expr a -> Expr a -> (Expr a, Expr a)
divMod n d = bool qr (q - 1, r + d) (signum r ==. negate (signum d))
where
qr@(q, r) = quotRem n d


-- | Perform integral division. Corresponds to the @div()@ function in
-- PostgreSQL, which behaves like Haskell's 'Prelude.quot' rather than
-- 'Prelude.div'.
quot :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
quot = function "div"


-- | Corresponds to the @mod()@ function in PostgreSQL, which behaves like
-- Haskell's 'Prelude.rem' rather than 'Prelude.mod'.
rem :: Sql DBIntegral a => Expr a -> Expr a -> Expr a
rem = function "mod"


-- | Simultaneous 'quot' and 'rem'.
quotRem :: Sql DBIntegral a => Expr a -> Expr a -> (Expr a, Expr a)
quotRem n d = (quot n d, rem n d)


-- | Round a 'DFractional' to a 'DBIntegral' by rounding to the nearest smaller
Expand Down
3 changes: 2 additions & 1 deletion src/Rel8/Type/Num.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import Prelude

-- rel8
import Rel8.Type ( DBType )
import Rel8.Type.Ord ( DBOrd )

-- scientific
import Data.Scientific ( Scientific )
Expand All @@ -39,7 +40,7 @@ instance DBNum Scientific
-- expressions. This is a Rel8 concept, and allows us to provide
-- 'fromIntegral'.
type DBIntegral :: Type -> Constraint
class DBNum a => DBIntegral a
class (DBNum a, DBOrd a) => DBIntegral a
instance DBIntegral Int16
instance DBIntegral Int32
instance DBIntegral Int64
Expand Down

0 comments on commit 2833c4b

Please sign in to comment.