For problems with types, here's a trick that has helped me immensely. Whenever I am completely baffled by a message like this, I do the following:
- If there's a type signature on the function in question, remove it and see if anything changes. If it compiles, ask ghci what the type is (using
:t
). If it doesn't compile, at least the error message may differ enough to give you another clue.
- If there's no type signature, add one. Even if it doesn't compile, the error message may give you another clue.
- If that doesn't help, then temporarily add type declarations on each of the expressions in the function. (Often you'll need to break up some of the expressions to see what's really going on. You may also need to temporarily enable the
ScopedTypeVariables
pragma.) Compile again and check the error messages.
That last one is more work, but I've learned a lot from that exercise. It usually pinpoints the exact place where there's a mismatch between what I think the type is and what GHC thinks the type is.
So let's begin by adding type signatures to your code:
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
Ah, now we get 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)
The problem is in the call to myrepli x n
. The function myrepli
expects a list/string, but you're passing it a single character. Change that last line to:
repli (x:xs) n = (myrepli [x] n) ++ (repli xs n)
At that point you will find other errors in your code. But rather than fix your code, let me show you another way to do it:
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)