views:

83

answers:

2

I just started learning Haskell and I ran into a problem in 2-adic type classes. Here's the important code:

data Rectangle = NoRect | Rect (Float,Float) (Float,Float) | Pane
      deriving (Show)
class Collision s1 s2 where
      collides ::  s1 -> s2 -> Bool

instance (Collision Rectangle Rectangle) where
    collides (Rect (aOrX, aOrY) (aCorX, aCorY)) 
             (Rect (bOrX,bOrY) (bCorX,bCorY)) = ...
    collides Pane _ = True
    ...

The compiler (GHC 6.12.1) now complains about Conflicting definitions for 'collides'

I don't see, how the definitions would conflict, do you?

Thanks!

A: 

I don't see it, if I use -XMultiParamTypeClasses then this compiles fine:

{-# OPTIONS -XMultiParamTypeClasses #-}
data Rectangle = NoRect | Rect (Float,Float) (Float,Float) | Pane
      deriving (Show)
class Collision s1 s2 where
      collides ::  s1 -> s2 -> Bool

instance (Collision Rectangle Rectangle) where
    collides (Rect (aOrX, aOrY) (aCorX, aCorY)) 
             (Rect (bOrX,bOrY) (bCorX,bCorY)) = False
    collides Pane _ = True
HaskellElephant
Nice, I've never seen `OPTIONS` before ... I always used `{-# LANGUAGE MultiParamTypeClasses #-}`.
Dario
@Dario it's very handy if you want to compile some files with different flags (-O2 , -fvia-c, -fexcess-precision), but still only use ghc --make for compiling =D.
HaskellElephant
@HaskellElephant: Yeah I see ... cool
Dario
+1  A: 

The most likely culprit is a layout error somewhere in your "..." that causes the two collides lines to be separated into two separate blocks. Conflicting definitions for 'collides' means that there are two different places in the same scope that are defining collides. Somehow either those two lines are interrupted so the compiler sees them as separate, or there's an error in the "..." part that somehow defines collides twice in one scope.

There are 2 main ways to trip the Conflicting definitions error. First, two bindings in the same function definition can try to bind the same variable, as in foo x x = .... That's not allowed, because it defines x twice.

The other (which is the one that I suspect applies in your code) is when two parts of the same definition are "interrupted" by another definition. The compiler sees that as two separate definitions. For example:

foo True = ...
bar = ...
foo False = ...

This is not allowed either, because it (again) defines the same name (foo) twice.

The interruption may not be obvious, especially in cases where you accidentally mix tabs and spaces (and your editor uses something other than the 8 tabs per space that Haskell assumes). It can appear in your editor to be an indented line in a where clause but due to differences in tab width the compiler sees it aligned with foo, making the second foo into another definition conflicting with the first.

It is generally considered a good idea in layout-sensitive languages to only use spaces in your code, or at the very least to make sure that your editor is using the right number of spaces for its tabs. For Haskell, that is 8.

mokus
Thanks! That helped :)
zombiecalypse