Haskell中的函数定义

5

我正在学习Haskell,使用的教材是《为了更好地学习Haskell!》(Learn You a Haskell for Great Good!),但是我犯了一个奇怪的错误,找不到原因。

这是我输入的代码:

let xs = [if x < 3 then "bang" else "boom" | x <- xs]

以下是GHCi中的错误文本:

No instance for (Num [Char])
arising from the literal `3'
Possible fix: add an instance declaration for (Num [Char])
In the second argument of `(<)', namely `(3)'
In the expression: x < (3)
In the expression: if x < (3) then "bang" else "boom"

但是当我输入以下内容时:
let boom xs = [if x < 3 then "bang" else "boom" | x <- xs]

这是书中的例子,我没遇到任何问题。

有人可以解释一下我的错误吗?


谢谢你们两个的回答,它们互相补充。 - guillaume8375
3个回答

13

您对xs的定义是递归的,也就是说您在其自身的定义中使用了xs。我不认为这是您想要的。

由于您在列表推导式中使用了"bang""boom",Haskell知道xs必须是字符串列表(因为xs等于列表推导式的结果)。此外,您说xxs的元素(x <- xs),因此x必须是字符串(即[Char])。然而,您却使用了x < 3,这意味着x是一个数字。错误信息的意思是"一个字符串不是一个数字"。


真糟糕,你比我快了几秒钟.. +1 - daniel gratzer

7

尝试为表达式指定类型。

xs = [if x < 3 then "bang" else "boom" | x <- xs]

因为xs是一个列表,我们还不知道它元素的类型,下面让我们来看一下。这个列表的元素是:

if x < 3 then "bang" else "boom"

这是一个类型为 String (又称为 [Char])的表达式。

因此 xs :: [String]。由于描述列表元素的表达式中的 x 是从列表 xs 中取出的,它也是一个 String,并用于比较。

if x < 3

现在,3 是一个整型字面量,因此它是多态的并且有类型。
3 :: Num a => a

所以从表达式x < 3中,我们得到:
  • 来自文字的Num约束,
  • 类型String的约束,因为x是从一个String列表中获取的。
因此,我们需要一个StringNum实例才能使表达式有良好的类型。通常情况下,String没有Num实例(有什么有用的实例呢?),所以你会得到一个类型错误。
如果xs是函数的参数,
boom xs = [if x < 3 then "bang" else "boom" | x <- xs]

没有理由让x的类型为String,因此这样可以正常工作。


感谢你们两位的回答,它们互相补充。 - guillaume8375

0
let xs = ... 

这意味着xs等于一个由"bang"和/或"boom"组成的列表,但条件规定这些元素应该进行<3的测试,这通常是使用数字而不是字符串完成的。

let boom xs =...

将函数“boom”与等式的右侧相等,其中参数“xs”是从中提取要测试是否小于3的元素的列表。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接