Haskell 99题第4题:编译器无法确定take函数返回值类型报错求助
Hey there! Let's work through this type inference issue you're hitting while tackling Haskell 99 Problems #4.
First, let's confirm the root cause you already spotted: when you compare take n xs and take (n+1) xs with ==, Haskell's compiler can't pin down what type those lists should be. The take function has the type Int -> [a] -> [a], but without extra context, the compiler doesn't know if a belongs to the Eq type class (required to use ==), or even what concrete type a is.
Here are three concrete solutions to fix this:
1. Add an Explicit Type Signature to Your Function
This is the cleanest and most recommended approach. By defining a type signature that specifies your input list's type must be an instance of Eq, you give the compiler the clarity it needs.
For example, if your function is calculating the length of a list (the goal of Problem #4), your code would look like this:
myLength :: Eq a => [a] -> Int myLength xs = go 0 xs where go n list | take n list == take (n+1) list = n | otherwise = go (n+1) list
The Eq a => constraint tells the compiler "a is a type that supports equality checks", so it knows comparing the results of take is valid.
2. Add a Local Type Annotation
If you don't want to define a full type signature for the function, you can annotate one of the take results to fix its type, which lets the compiler infer the other.
For a generic solution:
myLength xs = go 0 xs where go n list | take n list == (take (n+1) list :: Eq a => [a]) = n | otherwise = go (n+1) list
Or if you're working with a specific type (like integers), use a concrete annotation:
| take n list == (take (n+1) list :: [Int]) = n
This is less flexible than a full function signature, but it works for quick fixes.
3. Rewrite the Function to Avoid Comparing Lists Entirely
While your current approach works in theory, comparing entire sublists with take is inefficient for calculating length. A more idiomatic Haskell implementation skips this comparison entirely, and doesn't require the Eq constraint at all:
Basic Recursive Version
myLength :: [a] -> Int myLength [] = 0 myLength (_:xs) = 1 + myLength xs
Tail-Recursive Version (Better for Large Lists)
myLength :: [a] -> Int myLength xs = go 0 xs where go acc [] = acc go acc (_:ys) = go (acc + 1) ys
This approach counts elements directly, so there's no need for equality checks—meaning the compiler has no type ambiguity to resolve, and the function works for any list type, not just those that support ==.
内容的提问来源于stack exchange,提问作者Our

