以下是我写的一些定义,以避免混合货币
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
data EUR
data USD
newtype Amount a = Amount Double deriving (Fractional, Num, Show)
eur :: Double -> Amount EUR
eur = Amount
usd :: Double -> Amount USD
usd = Amount
usd 34 + usd 3
按预期进行类型检查usd 33 + eur 33
是预期的编译错误usd 33 + 3
是可以的。我想避免的东西,并且不明白。我怀疑这是因为Num
实例,但那么第二种情况有什么不同?你能解释为什么usd 33 + 3
编译,以及是否有可能使类型检查器拒绝这个表达式。
答案 0 :(得分:12)
Haskell中的数字有很多隐含性。在心理上,您应该用3
替换fromInteger 3
之类的每个数字。由于Amount
使用GeneralizedNewtypeDeriving
作为Num
类型类的一部分,因此它会继承fromInteger
个实例。所以编译器正在这样做
usd 33 + 3
=== [implicit fromInteger & expand usd]
(Amount 33 :: Amount USD) +
fromInteger 3
=== [fromInteger :: Num a => a -> Amount a]
(Amount 33 :: Amount USD) +
(Amount 3 :: Amount a)
=== [unify a]
(Amount 33 :: Amount USD) +
(Amount 3 :: Amount USD)
答案 1 :(得分:2)
当GHC派生Num
类时,它提供了一个实现
fromInteger
功能。像3
这样的整数文字实际上具有Num a => a
类型。
ghci> :t (34)
(34) :: Num a => a
当类型检查器发现您正在尝试添加类型值时
Amount USD
到3
,它确定3 :: Amount USD
,这是有效的
它是Num
类型类的成员。