为什么这个Haskell表达式编译?

Jea*_*ier 3 haskell typechecking phantom-types

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

{-# 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
Run Code Online (Sandbox Code Playgroud)
  • usd 34 + usd 3 按预期进行类型检查
  • usd 33 + eur 33 是预期的编译错误
  • usd 33 + 3根据编译器,我很惊讶但是没关系.我想避免的东西,并且不明白.我怀疑这是因为Num实例,但那么第二种情况有什么不同?

你能解释为什么usd 33 + 3编译以及是否有可能使类型检查器拒绝这个表达式.

J. *_*son 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)
Run Code Online (Sandbox Code Playgroud)