I have the following piece of code in Haskell:
addm a b m = fromInteger $ mod (fromIntegral a + fromIntegral b) (fromIntegral m)
The idea is that, if the type of a, b and m doesn't have enough bits such that the addition could wrap (e.g. if using Word8), then the calculation would be incorrect. So, to prevent this, we convert temporarily to Integer, do the calculation and then convert back.
Is there a more succinct way to write this without the three fromIntegral and one fromInteger ?
Expanding on augustuss's comment:
addm a b m = i $ mod (i a + i b) (i m)
where i = fromIntegral
(fromInteger and fromIntegral work identically on Integers, so we can replace fromInteger with fromIntegral).
For one thing, you should use toInteger and fromInteger, since fromIntegral will convert to Num, not Integer. Unfortunately there isn't a particularly friendly way to do it, but with a few combinators you can make it shorter:
import Data.Function (on)
addm a b m = fromInteger $ flip mod (toInteger m) $ on (+) toInteger a b
But with the operator
infixr 9 .:
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) = (.).(.)
you can define it as (if you make m the first argument)
addm m = fromInteger .: flip mod (toInteger m) .: on (+) toInteger
But at this point it's somewhat difficult to make it more pointfree without making it unreadable. Casting in Haskell is always explicit, you can't get around it. Some of the names simply make it a bit verbose, but you gain type safety from it. Personally, I would probably instead define two versions of this function, one specific to Integer and the other generalized to Integral:
addm :: Integral a => a -> a -> a -> a
addm a b m = fromInteger $ addmInteger (toInteger a) (toInteger b) (toInteger m)
where
addmInteger :: Integer -> Integer -> Integer -> Integer
addmInteger a' b' m' = (a' + b') `mod` m'
While this is more typing, it cleanly separates the logic from the type casting. You could shorten this with a combinator similar to on:
addm :: Integral a => a -> a -> a -> a
addm a b m = fromInteger $ on3 addmInteger toInteger a b m
where
on3 :: (b -> b -> b -> c) -> (a -> b) -> a -> a -> a -> c
on3 f g x y z = f (g x) (g y) (g z)
addmInteger :: Integer -> Integer -> Integer -> Integer
addmInteger a' b' m' = (a' + b') `mod` m'
Although this is more total code. I personally still like it better because on3 could be used elsewhere easily, and the business logic is still separated from the casting.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With