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.