对于类型问题,这里有一个对我帮助很大的技巧。每当我对这样的消息完全感到困惑时,我会执行以下操作:
- 如果有问题的函数上有类型签名,请将其删除并查看是否有任何更改。如果它编译,询问 ghci 类型是什么(使用
:t
)。如果它没有编译,至少错误消息可能会有所不同,足以给你另一个线索。
- 如果没有类型签名,请添加一个。即使它没有编译,错误信息也可能会给你另一个线索。
- 如果这没有帮助,则暂时在函数中的每个表达式上添加类型声明。(通常您需要分解一些表达式以查看实际情况。您可能还需要临时启用
ScopedTypeVariables
pragma。)再次编译并检查错误消息。
最后一个是更多的工作,但我从那个练习中学到了很多东西。它通常会指出我认为的类型与 GHC 认为的类型之间存在不匹配的确切位置。
因此,让我们首先在代码中添加类型签名:
myrepli :: [a] -> Int -> [a]
myrepli [] n = []
myrepli [x] 0 = []
myrepli [x] n = (x:(myrepli [x] (n-1)))
repli :: [a] -> Int -> [a]
repli [] n = []
repli (x:xs) n = (myrepli x n) ++ (repli xs n) -- triggers a compiler error
啊,现在我们得到一个编译器错误:
amy.hs:9:27:
Couldn't match expected type `a' with actual type `[a]'
`a' is a rigid type variable bound by
the type signature for repli :: [a] -> Int -> [a] at amy.hs:7:10
In the first argument of `myrepli', namely `x'
In the first argument of `(++)', namely `(myrepli x n)'
In the expression: (myrepli x n) ++ (repli xs n)
问题在于对myrepli x n
. 该函数myrepli
需要一个列表/字符串,但您传递给它一个字符。将最后一行更改为:
repli (x:xs) n = (myrepli [x] n) ++ (repli xs n)
此时,您会在代码中发现其他错误。但是,与其修复您的代码,让我向您展示另一种方法:
repl (x:xs) n = (myReplicate x n) ++ (repl xs n)
repl [] _ = []
-- You could use the library function "replicate" here, but as a
-- learning exercise, we'll write our own.
myReplicate a n = take n (repeat a)