In fact, the function that you asked in the question compiles fine. You would get the error you indicated if you had:
myzip :: [a] -> [b] -> [(a, b)] myzip (a:b) (z:g) | b == [] = [] | g == [] = [] | otherwise = (a, z) : myzip bg
With an explicit type signature saying that myzip works on a list of any types a and b . But you used b == [] and g == [] . The equality operator is not defined for any type, only for types that are members of a class of type Eq , so the code you wrote does not match the type you specified.
This is what the error message says quite straightforward, but if you're just learning and haven't gotten used to it yet, enter a little unclear.
If you change the type signature for myzip to say that a and b must be members of a class of type Eq , then the code you gave will work:
myzip :: (Eq a, Eq b) => [a] -> [b] -> [(a, b)]
Or, if you completely disable the type signature (as in the question), GHC actually passes this type from the fact that you used the == operator, and the code just compiles as-is.
However, checking if the list is empty can be done without using the == operator, so you can write myzip to really work on any types a and b . One way is to use the null function:
myzip :: [a] -> [b] -> [(a, b)] myzip (a:b) (z:g) | null b = [] | null g = [] | otherwise = (a, z) : myzip bg
But a much more common way is to simply use several equations to determine myzip , with basic cases matching the pattern [] , and the main case, which assumes the lists are not empty:
myzip :: [a] -> [b] -> [(a, b)] myzip (a:[]) _ = [] myzip _ (z:[]) = [] myzip (a:b) (z:g) = (a, z) : myzip bg
Note that this style also made it obvious that there is a bug in your implementation. You drop the last a or z , and there is no case where the lists are completely empty!
When your equation said myzip (a:b) (z:g) and then checked b and g against an empty list, it was actually too late. You do not need to check if there is b [] , you need to check if the whole list was empty. But you already assumed that it is not empty and laid it out on a:b . This causes your code to (a) return an incorrect result, since it discards the last pair of elements that it should pin, and (b) throws an error when one of the arguments is an empty list.
Recursion in lists usually looks more:
myzip :: [a] -> [b] -> [(a, b)] myzip [] _ = [] myzip _ [] = [] myzip (a:b) (z:g) = (a, z) : myzip bg
This behaves correctly.