为什么要编译这个Haskell表达式?
这里是我写的一些定义,以避免混合货币为什么要编译这个Haskell表达式?,haskell,typechecking,phantom-types,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 34美元+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
34美元+3美元
是一个预期的编译错误33美元+33欧元
- 我很惊讶,但是根据编译器的说法,
还可以。我想避免的事,我不明白。我怀疑这是因为33美元+3
instance,但是第二种情况有什么不同呢Num
你能解释一下为什么
USD33+3
会编译,以及是否有可能让类型检查器拒绝这个表达式。Haskell中的数字有很多隐含性。从精神上讲,你应该用整数3的替换像3
这样的每个数字。由于Amount
使用GeneralizedNewtypeDeriving
作为Num
typeclass的一部分,因此它继承了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)
当GHC派生Num
类时,它为
fromInteger
函数。像3
这样的整数文本实际上具有类型Num a=>a
ghci> :t (34)
(34) :: Num a => a
当类型检查器看到您正在尝试添加类型为的值时
Amount USD
到3
,它确定3::Amount USD
,自
它是Num
typeclass的成员。那是什么∀ 十,。x⊦ ...代码>比特?@tel,这是我的GHCI提示。我可以看出哪里会令人困惑。Num
type类不是。它适用于可能包含整数的数据类型,并且以与整数兼容的方式支持原始数字运算。所以你真正想要的是一个或多个“数学符号”类(加、减、乘、除等)。许多EDSL都定义了自己的中缀运算符,例如+
、-
和*
,以避免使用笨拙的Num
类。不过,我不确定这是否真的是一个致命的问题。实际上,事实证明,拥有自定义类型的文本很少有关系,因为除非声明为多态,否则它们仍然不是多态的。