Cristian Garcia
Cristian Garcia

Reputation: 9859

Error with a Class in Haskell

I've been trying to learn classes in haskell with a little program to manipulate representation of a linear equation, but I get an error I dont understand. Can somebody tell me why this code

{-# LANGUAGE FlexibleInstances #-}

data Line = Line { m :: Double, b :: Double } deriving( Show, Eq )

class Perpendicular a where
  perpendicular :: a -> Line

instance Perpendicular (Line -> Double) where
  perpendicular (Line m b) b2 = Line m2 b2
    where m2 = (-1/m)

gives me this error

Couldn't match expected type `Line -> Double'
            with actual type `Line'
In the pattern: Line m b
In an equation for `perpendicular':
    perpendicular (Line m b) b2
      = Line m2 b2
      where
          m2 = (- 1 / m)
In the instance declaration for `Perpendicular (Line -> Double)'

It looks as if its ignoring b2.

Upvotes: 0

Views: 74

Answers (1)

bheklilr
bheklilr

Reputation: 54068

You have written your instance as

instance Perpendicular (Line -> Double) where ...

So that means that a ~ (Line -> Double). perpendicular is a function with the type a -> Line, so for this instance it would have the concrete type (Line -> Double) -> Line. That means its first argument has to be a function that takes a Line and returns a Double. You've provided it the arguments Line m b and b2, implying that perpendicular should have the type Line -> Double -> Line, which is an entirely different type. This is because -> is right associative, meaning the following types are equivalent

a ->  b ->  c -> d
a ->  b -> (c -> d)
a -> (b -> (c -> d))
a -> (b ->  c -> d)

But these aren't

  a -> b  -> c  -> d   -- These are not equivalent!!
 (a -> b) -> c  -> d   -- These are not equivalent!!
((a -> b) -> c) -> d   -- These are not equivalent!!
 (a -> b  -> c) -> d   -- These are not equivalent!!

What it looks like you want is a function that takes variable arguments. This is not the easiest thing to do in Haskell, and can lead to a lot of boilerplate and complex data structures, potentially harming efficiency while sacrificing type safety. You could get around this somewhat by taking advantage of tuples, something like

instance Perpendicular (Line, Double) where
    perpendicular (Line m b, b2) = Line (-1 / m) b2

instance Perpendicular Line where
    perpendicular line = perpendicular (line, 0 :: Double)

Note, this still requires FlexibleInstances, and the type annotation on 0 is also required. This is still making typeclasses do things they weren't meant for, but it is legal code. You will also have to annotate a value anytime it doesn't have a declared type, e.g.

> perpendicular (Line 1 0, 5 :: Double)
Line {m = -1.0, b = 5.0}
> perpendicular (Line 1 0, 5)
    No instance for (Perpendicular (Line, t0))
      arising from a use of `perpendicular'
    The type variable `t0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there is a potential instance available:
      instance Perpendicular (Line, Double)
        -- Defined at <interactive>:11:10
    Possible fix:
      add an instance declaration for (Perpendicular (Line, t0))
    In the expression: perpendicular (Line 1 0, 5)
    In an equation for `it': it = perpendicular (Line 1 0, 5)

Upvotes: 5

Related Questions