为什么作为值的局部变量的类型会影响函数类型签名中输入变量的类型?
Prelude> func f = [(show s, f == s) | s <- [0, 1..10]]
Prelude> :type func
func :: (Num a, Enum a, Show a, Eq a) => a -> [(String, Bool)]
我希望f只是一个实例,Eq a但由于某种原因,所有应用到的类约束s也被应用到f。更换s任何常量消除了对相关类型的约束f,并取代s在平等去除所有的除外限制类Eq a的f。
有人可以向我解释为什么作为值的局部变量的类型会影响作为值的输入变量的类型吗?
回答
Eq不存在于真空中。要比较两件事是否相等,你必须有两件事。而且,至关重要的是,这两件事必须属于同一类型。在 Haskell 中,0 == "A"不仅是假的;这是一个类型错误。从字面上看是没有意义的。
f == s
当编译器看到这个时,即使它对fand的类型一无所知s,它也知道是什么(==)。(==)是具有以下签名的函数。
(==) :: Eq a => a -> a -> Bool
两个参数的类型相同。所以,现在直到永远,为类型检查该表达式的其余部分,我们必须有f与s相同类型的。任何需要的s也是需要的f。并s从[0, 1..10]. 您的类型约束如下
Num是必需的,因为s从文字整数列表中获取值。Enum是[..]列表枚举语法所必需的。Show由 要求show s。Eq是f == s等式表达式所必需的。
现在,如果我们s用常量替换,我们会得到类似
func f = [(show s, f == 0) | s <- [0, 1..10]]
现在f正在与0. 它与 无关s。f需要Eq(for (==)) 和Num(因为我们正在与零比较,一个数字)。s,在另一方面,要求Enum,Num,Eq,和Show。抽象地说,这实际上应该是一个类型错误,因为我们没有给出s应该是哪种类型的指示,也没有足够的线索来弄清楚。但是输入默认值,我们会Integer摆脱它。