理解Haskell类型系统

理解Haskell类型系统,haskell,Haskell,我有三个函数 boombangs xs = [if x < 10 then "BOOM" else "BANG" | x <- xs odd x] length' xs = sum [1 | _ <- xs] removeNonUppercase st = [x | x <- st, x `elem` ['A'..'Z']] 当我将int数组传递给removeNonUppercase或将字符串传递给boombangs时,Haskell应该给我一个错误。它也是,但是当

我有三个函数

boombangs xs = [if x < 10 then "BOOM" else "BANG" | x <- xs odd x]

length' xs = sum [1 | _ <- xs]

removeNonUppercase st = [x | x <- st, x `elem` ['A'..'Z']]
当我将int数组传递给removeNonUppercase或将字符串传递给boombangs时,Haskell应该给我一个错误。它也是,但是当我没有在任何地方指定类型时,它怎么知道它错了呢

此外,为什么Boombang和removeNonUppercase的类型不同,即使它们使用相同的输入

如果这个问题显得含糊不清或完全无知,我道歉。我刚刚开始学习Haskell,我正慢慢地围绕着这个主要用C和python编程的范例思考


如需了解更多有关haskell和类型系统的信息,请参阅任何资源。

对于boombangs,您向x应用的运算符可以看出它不能是字符串。对于removeNonUpperCase,可以看到元素必须在['A'..'Z']中,因此不能是int。这也解释了为什么它们不能在相同的输入上工作。

GHC使用类型推断来尝试猜测您的函数可以是什么类型

在boombangs中,它可以告诉您传递列表是因为xa,因为您对每个元素应用了奇数。它知道您正在返回一个字符串列表,因为列表中出现了文字上的隆隆声

在“长度”中,您的类型仅受sum约束,它需要Num a=>[a]。您的输入类型是任何类型的列表,因为您实际上没有对元素本身执行任何操作,但您确实指示参数是由 当我没有在任何地方指定类型时,它怎么知道它错了呢

Haskell编译器(在您的例子中是GHC)可以进行类型推断,这意味着它几乎总是可以通过上下文信息确定表达式的类型。比如说,

mbangs xs = [if x < 10 then "BOOM" else "BANG" | x <- xs, odd x]
您可以手动推断其类型,如下所示:

您通过列表理解定义mbang,因此xs必须是一个列表,并且

在xs的元素上应用odd,因此xs的类型必须是Integral a=>[a],因为odd的类型是Integral a=>a->Bool

另外,对于xs的每个元素,如果x<10,则通过输出函数生成一个字符串

因此,mbang的类型必须是整数a=>[a]->[[Char]],正如ghci刚刚告诉您的那样

为什么Boombang和removeNonUppercase的类型不同,即使它们使用相同的输入


因为你在他们的列表理解定义中使用了不同的输出函数。

这对我来说有点迷人。作为跟进,您能否告诉我为什么长度的类型是length:[a]->Int,而我的length“具有更长的长度”::Num a=>[t]->a。我想你的答案表明我的长度“有一点Num,因为求和函数。内置长度与此有何区别。它能在我的函数不能的类型上运行吗?内置的length函数提供了它的类型签名,使用Int而不是Integer、Float或Double更有效。内置定义也不同于您的定义,但它基本上仍然基于+。+的类型是Num a=>a->a->a,因为我们希望该运算符处理所有数字,而不仅仅是Int。类型签名之间唯一的真正区别是内置使用了Num的具体实例,而您的实例更一般。在实践中,让它更通用是没有用的。因此,函数的类型包括其输入和输出。输出是类型中->之后的位吗?
mbangs xs = [if x < 10 then "BOOM" else "BANG" | x <- xs, odd x]