简体   繁体   English

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

[英]Why does this Haskell expression compile?

Here are some definitions I wrote, to avoid mixing currencies 以下是我写的一些定义,以避免混合货币

{-# 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 type checks as expected usd 34 + usd 3类型检查按预期
  • usd 33 + eur 33 is a compilation error as expected usd 33 + eur 33是预期的编译错误
  • I'm surprised but usd 33 + 3 is OK according to the compiler. 我很惊讶,但根据编译器我们usd 33 + 3是可以的。 Something I wanted to avoid, and don't understand. 我想避免的东西,并且不明白。 I suspect it is because Num instance, but then what is the difference with the second case? 我怀疑这是因为Num实例,但那么第二种情况有什么不同?

Can you explain why usd 33 + 3 compiles and if it is possible to make the type-checker reject this expression. 你能解释一下为什么我们usd 33 + 3编译,如果有可能使类型检查器拒绝这个表达式。

Numbers in Haskell have lots of implicitness. Haskell中的数字有很多隐含性。 Mentally, you ought to replace every number literal like 3 with fromInteger 3 . 在心理上,你应该用fromInteger 3替换像3这样的每个数字。 Since Amount uses GeneralizedNewtypeDeriving to be part of the Num typeclass, it inherits a fromInteger instance. 由于Amount使用GeneralizedNewtypeDeriving作为Num类型类的一部分,因此它继承了一个fromInteger实例。 So the compiler is doing this 所以编译器正在这样做

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)

When GHC derives the Num class, it provides an implementation for the fromInteger function. 当GHC派生Num类时,它为fromInteger函数提供了一个实现。 Integer literals like 3 actually have the type Num a => a . 3这样的整数文字实际上具有类型Num a => a

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

When the type checker sees that you are trying to add a value of type Amount USD to 3 , it determines 3 :: Amount USD , which is valid since it is a member of the Num typeclass. 当类型检查器发现您尝试将Amount USD类型的值添加到3 ,它确定3 :: Amount USD ,这是有效的,因为它是Num类型类的成员。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM