Haskell 为什么此表达式具有有效类型?
在Haskell 为什么此表达式具有有效类型?,haskell,ghci,Haskell,Ghci,在ghci中翻来覆去,我碰巧注意到表达式(*)1[1..5]显然有一个有效的类型 :t (*) 1 [1..5] (*) 1 [1..5] :: (Enum t, Num [t], Num t) => [t] 很明显,它是一个包含多个类型约束的列表,包括Num[t],在我看来这是不可能的,好像它应该给出一个错误 这是表达式的类型吗?为什么ghci的:t命令在这里没有给出错误?Num[t]不仅是可能的,而且很容易: import Control.Applicative liftA0 = p
ghci
中翻来覆去,我碰巧注意到表达式(*)1[1..5]
显然有一个有效的类型
:t (*) 1 [1..5]
(*) 1 [1..5] :: (Enum t, Num [t], Num t) => [t]
很明显,它是一个包含多个类型约束的列表,包括Num[t]
,在我看来这是不可能的,好像它应该给出一个错误
这是表达式的类型吗?为什么ghci的
:t
命令在这里没有给出错误?Num[t]
不仅是可能的,而且很容易:
import Control.Applicative
liftA0 = pure -- hobgoblins, simple minds, etc.
liftA1 = fmap
instance Num t => Num [t] where
(+) = liftA2 (+)
(-) = liftA2 (-)
(*) = liftA2 (*)
negate = liftA1 negate
abs = liftA1 abs
signum = liftA1 signum
fromInteger n = liftA0 (fromInteger n)
因此,GHC产生错误而不是推断您的表达式可以通过适当的实例很好地键入,这将是非常糟糕的
当然,用真正的代码编写这个实例也很糟糕,但GHC不应该像我们人类那样对代码进行判断。让我们看看这些约束是如何解释类型的 数字 在Haskell中,文字数字被替换为调用
fromInteger
(或者fromRational
,如果其中有小数点或“e”)。这样我们就可以写“1”,让它成为float、double、int或其他形式。fromInteger的类型为
fromInteger :: Num a => a
因此1
将从Integer(1::Integer)
中删除的值,该值的类型为Num t=>t
范围
在Haskell中,语法[a..b]
转换为调用enumFromTo a b
,类型为enumFromTo::Enum a=>a->a->[a]
。把这些放在一起,我们得到
[1..5] == enumFromTo (fromInteger 1) (fromInteger 5) :: (Enum a, Num a) => [a]
把它们放在一起
现在,(*)
的类型是numb=>b->b->b
,因此我们将这些组合在一起得到:
(Num t,
Num a,
Enum a,
Num b,
t~b,
[a]~b) => b
请注意,a~b
表示a
和b
的类型相同。将这些元素组合在一起,就得到了类型
(Num a, Enum a, Num [a]) => [a]
可以为[]定义一个Num实例,使其行为类似于多项式(即前导0的无限序列),这对于在实际代码中编写并不可怕。abs
和signum
会有点尴尬。@gallais这些定义不需要有用,只要一致即可signum x=[1]
和abs=id
可能足以满足此类实例的大多数预期用途。在这种情况下,最好是未定义的
,不是吗?如果你错误地使用这些无意义的函数(abs
和signum
有规律可循),至少你会在运行时出错@mb14我认为这样做仍然很糟糕;至少用newtype
来掩饰你的羞耻。