
El vie, 27-08-2010 a las 01:58 -0700, Greg escribió:
Hi--
More silly typeclass questions. I'm not sure the right way to ask it, so I'll start with a failed code snippet:
data Foo a = Foo a
class TwoPi a where div2pi :: (Floating b) => a -> b
instance (Floating a) => TwoPi (Foo a) where div2pi (Foo a) = a / (2*pi)
a/(2*pi) has type Floating a => a, where a is the type of a in Foo a. the class declaration however requires to be able to return a value of type Floating b => b for any type b, no relation to a whatsoever.
instance TwoPi Float where div2pi a = a / (2*pi)
a/(2*pi) has type Float (because a has type Float), so this again can not work.
You would need a function f::(Floating b) => Float -> b for this to work. In the former, you would need a function f::(Floating a, Floating b) => a -> b.
This code is obviously meaningless, but I'm trying to figure out how you can create instances of a typeclass for data types of different kinds.
I have a similar piece of code that works:
data Foo a = Foo a
class Testable a where isPos :: a -> Bool
instance (Ord b, Num b) => Testable (Foo b) where isPos (Foo b) = b > 0
b > 0 has type Bool, no matter what type of number b is. so this is ok.
instance Testable Float where isPos a = a > 0
same here
One obvious difference is that the type of isPos is a -> Bool, with a defined type as the return. I'd rather not commit to a specific Floating type up front (I'd prefer sometimes Float sometimes Double, depending on the 'a' in Foo a, but trying to declare it as Float doesn't help me. This fails:
data Foo a = Foo a
class TwoPi a where div2pi :: a -> Float
instance (Floating b) => TwoPi (Foo b) where div2pi (Foo b) = b / (2*pi)
b/(2*pi) has type Floating b => b, not Float. You would need a function of type Floating b => b -> Float.
instance TwoPi Float where div2pi a = a / (2*pi)
This is ok
What is the difference between these last two cases ("a -> Bool" and "a -> Float"),
The difference is not between these type, but between (>), and (/). (>) returns Bool, no matter the type of its arguments. (/) returns sth of the same type as its arguments.
and is there anyway to make "a -> b" work?
The closest is probably using a function like: realToFrac::(Real a, Fractional b) => a -> b
then you can write sth like data Foo a = Foo a class TwoPi a where div2pi :: (Floating b) => a -> b instance (Real a, Floating a) => TwoPi (Foo a) where div2pi (Foo a) = a / (2*pi) Jürgen