Reputation: 9859
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
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