一方面,您应该使用toInteger 和fromInteger,因为fromIntegral 将转换为Num,而不是Integer。不幸的是,没有一种特别友好的方法可以做到这一点,但是使用一些组合器可以使其更短:
import Data.Function (on)
addm a b m = fromInteger $ flip mod (toInteger m) $ on (+) toInteger a b
但是有运营商
infixr 9 .:
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) = (.).(.)
您可以将其定义为(如果您将m 作为第一个参数)
addm m = fromInteger .: flip mod (toInteger m) .: on (+) toInteger
但是在这一点上,让它变得更无意义而不使其不可读有点困难。在 Haskell 中强制转换总是明确的,你无法绕过它。有些名字只是让它有点冗长,但你可以从中获得类型安全。就个人而言,我可能会改为定义此函数的两个版本,一个特定于Integer,另一个泛化为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'
虽然这是更多类型的输入,但它清晰地将逻辑与类型转换分开。您可以使用类似于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'
虽然这是更多的总代码。我个人还是更喜欢它,因为on3 可以很容易地在其他地方使用,并且业务逻辑仍然与强制分离。