不在范围内:键入构造函数或类 '-'(以及反转列表时的其他错误)



我正在阅读"七周内的七种语言"一书,Haskell第一天的问题之一是">编写一个函数,该函数接受一个列表并反向返回相同的列表"。

我的第一个实现工作正常:

reverseList :: [a] -> [a]
reverseList [] = []
reverseList [x] = [x]
reverseList (h:t) = reverseList(t) ++ [h]

然后我想到了另一种方法,我试图实现为:

reverseList1 :: [a] -> [a]
reverseList1 [] = []
reverseList1 [x] = [x]
reverseList1 l = last(l) :: reverseList1(take(length(l)-1)(l))

(也就是说 - 取最后一个元素,然后将颠倒的第一个元素附加到它后面(。但是,当我尝试加载文件时,这给了我一个错误(实际上是三个(:

[1 of 1] Compiling Day1             ( day1.hs, interpreted )
day1.hs:35:49: error: Not in scope: type constructor or class ‘-’
|
35 |   reverseList1 l = last(l) :: reverseList1(take(length(l)-1)(l))
|                                                 ^^^^^^^^^^^
day1.hs:35:49: error:
Illegal operator ‘-’ in type ‘length (l) - 1’
Use TypeOperators to allow operators in types
|
35 |   reverseList1 l = last(l) :: reverseList1(take(length(l)-1)(l))
|                                                 ^^^^^^^^^^^
day1.hs:35:59: error:
Illegal type: ‘1’ Perhaps you intended to use DataKinds
|
35 |   reverseList1 l = last(l) :: reverseList1(take(length(l)-1)(l))
|                                                           ^
Failed, no modules loaded.

谷歌搜索"不在范围内"错误表明我正在尝试使用尚未导入的东西 - 我认为我不需要根据其他实验明确导入"减法"。

我不明白第二个错误(Use TypeOperators to allow operators in types( - 我从这里看到TypeOperators是我可以在ghci上设置的标志,但我没有尝试在类型中使用运算符 -length(l)-1(据我所知(是take的参数,而不是类型。

谷歌搜索"也许你打算使用 DataType"让我来到这里 -我希望我的代码不会像那个例子那样被撕裂,但有可能我同样一无所知!


基于这里的最后一个示例,我还尝试了:

reverseList1 l = last(l) :: reverseList1(take(takeLength)(l))
where takeLength = length(l)-1

(给出了一个(非常冗长!(错误,以"无法匹配类型'a'"开头(和

reverseList1 l =
let takeLength = length(l)-1 in
in last(l) :: reverseList1(take(takeLength)(l))

哪个给了

day1.hs:40:5: error: parse error on input ‘in’
|
40 |     in last(l) :: reverseList1(take(takeLength)(l))
|     ^^
Failed, no modules loaded.

列表是用:构造的。::表示一个类型,因此Haskell试图将其读取为类型,因此出现了错误。

更正后的代码是:

reverseList1 :: [a] -> [a]
reverseList1 [] = []
reverseList1 [x] = [x]
reverseList1 l = last l : reverseList1 (take (length l - 1) l)

请注意使代码更具可读性的括号!

在第二次尝试中,您编写in两次,解析器会感到困惑。

更正后的代码是:

reverseList1 l =
let takeLength = length l - 1
in last l : reverseList1 (take takeLength) l

现在,这个错误实际上很有趣。TypeOperators扩展是允许(不出所料(在类型声明中使用中缀运算符的扩展。

在这里,编译器注意到-看起来像一个中缀运算符,并且考虑到它是在符号类型中推断您可能打算使用TypeOperators扩展名。当然,这里的情况并非如此!

至于DataKinds,这是一个相当高级的扩展,允许您将数据(如1"Hello"等(放在类型中。我不会在这里确切讨论它的用途,但编译器提到它的原因是您在类型签名中使用了1,该类型签名只能与DataKinds扩展一起使用。

最新更新