3

这是我写的一些定义,以避免混合货币

{-# 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编译以及是否可以让类型检查器拒绝这个表达式。

4

2 回答 2

12

Haskell 中的数字有很多隐含性。从心理上讲,您应该将每个数字文字替换3fromInteger 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)
于 2013-07-24T21:24:52.147 回答
2

当 GHC 派生Num类时,它提供了 fromInteger函数的实现。像这样的整数文字3实际上有 type Num a => a

ghci> :t (34)
(34) :: Num a => a

当类型检查器看到您正在尝试将类型的值添加 Amount USD到 时3,它会确定3 :: Amount USD,这是有效的,因为它是类型类的成员Num

于 2013-07-24T21:26:16.367 回答