[英]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
是预期的编译错误 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.