Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 为什么此表达式具有有效类型?_Haskell_Ghci - Fatal编程技术网

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
来掩饰你的羞耻。