views:

362

answers:

2

I wrote the following code in Haskell to compute the dot product of two vectors, but cannot compile it due to the following error:

cannot construct infinite type: a = [a] When generalising the type(s) for dot'

dot :: (Num a) => [a] -> [a] -> a

[] `dot` [] = 0
x@[xi,xs] `dot` y@[yi,ys] = xi*yi + (xs `dot` ys)

I've taken a look at this question in advance for guidance. As far as I can tell, the types are correct. x, y and the two []'s are lists, and the function returns a number.

What's wrong?

+6  A: 

You're confusing the syntax for a two element list [x, y] with the syntax for splitting a list into the first element and the rest of the list (x:y). Try this instead:

dot :: (Num a) => [a] -> [a] -> a

[] `dot` [] = 0
x@(xi:xs) `dot` y@(yi:ys) = xi*yi + (xs `dot` ys)

The @ patterns are also unnecessary, btw.

Ganesh Sittampalam
Thanks a lot, that did the trick.
Zaid
+7  A: 

Ganesh' answer is spot on. Let me briefly elaborate on the meaning of an "infinite type".

dot has this type definition:

dot :: (Num a) => [a] -> [a] -> a

This means that dot takes two lists of Num elements and returns a Num. Your definition includes this line:

x@[xi,xs] `dot` y@[yi,ys] = xi*yi + (xs `dot` ys)

Since, as Ganesh points out, [xi,xs] is a list consisting of two elements, xi and xs should be Nums. Same for yi and ys. But then they are passed as arguments to dot:

xs `dot` ys

This means that xs and ys must be lists of Nums. That leads to a contradiction.


Another way to look at this, is to for a moment forget about the type definition of dot. This line,

x@[xi,xs] `dot` y@[yi,ys] = xi*yi + (xs `dot` ys)

states that dot takes two lists whose elements are appropriate arguments to dot. But the only way for that to make sense, is if these lists are infinitely nested. That is not allowed nor sensible.

Stephan202
@Stephan: Thanks for the explanation. I think that clears up why even the [xi:xs] notation failed, as the xs `dot` ys would imply that xs and ys are lists of lists...Let me know if my interpretation is valid.
Zaid
@Zaid: that is correct. If `xi :: a`, then `(xi:xs) :: [a]` and `[xi:xs] :: [[a]]`. Thus matching on `[xi:xs]` and then recursively passing `xs` will indeed lead to an *infinite type* error.
Stephan202