Skip to content

stimesDefault, stimesIdempotent etc throw exception on Integral types without a zero.

For example

data BinP -- also called Pos
    = BE
    | B0 BinP
    | B1 BinP

like in bin package or just

newtype Natural1 = N1 Natural

instance Integral N1 where
    toInteger (N1 n) = 1 + toInteger n

With these

*Data.Bin Data.Semigroup> stimes (1 :: Integer) "foo"
"foo"
*Data.Bin Data.Semigroup> stimes (2 :: Integer) "foo"
"foofoo"
*Data.Bin Data.Semigroup> stimes (3 :: Integer) "foo"
"foofoofoo"
*Data.Bin Data.Semigroup> stimes (1 :: BinP) "foo"
"*** Exception: arithmetic underflow
*Data.Bin Data.Semigroup> stimes (2 :: BinP) "foo"
"*** Exception: arithmetic underflow
*Data.Bin Data.Semigroup> stimes (3 :: BinP) "foo"
"*** Exception: arithmetic underflow

The stimesDefault is defined as

stimesDefault :: (Integral b, Semigroup a) => b -> a -> a
stimesDefault y0 x0
  | y0 <= 0   = errorWithoutStackTrace "stimes: positive multiplier expected"
  | otherwise = f x0 y0 where f ...

but I think it can be as well defined as

stimesDefault :: (Integral b, Semigroup a) => b -> a -> a
stimesDefault y0 x0
  | y0 >= 1   = f x0 y0 where ...
  | otherwise = errorWithoutStackTrace "stimes: positive multiplier expected"

and similarly for stimesIdempotent

Fixing mtimesDefault would be trickier as it is defined as

stimesIdempotentMonoid :: (Integral b, Monoid a) => b -> a -> a
stimesIdempotentMonoid n x = case compare n 0 of
  LT -> errorWithoutStackTrace "stimesIdempotentMonoid: negative multiplier"
  EQ -> mempty
  GT -> x

and using compare is probably very welcome, although for types people care about, like Int or Integer, or even BinP or Natural/1, having n >= 1 first case is probably a win.

Edited by Oleg Grenrus
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information