[Haskell-beginners] instances of different kinds

Greg greglists at me.com
Fri Aug 27 22:58:44 EDT 2010


I'm still having a hard time finding a way to make this work, even given the fine suggestions from Tobias and Jürgen.  I suspect there's some piece of information that the compiler can't make sense of that I'm just not seeing-- a case of it insisting on doing what I say instead of what I mean...  =)

I guess the problem I'm having is finding a way to treat parametric and non-parametric types interchangeably.  The syntax doesn't seem to exist that will allow me to say:

div2pi :: (Floating a) => a -> a   -- for non parametric types (ie. Float)
and
div2pi :: (Floating b) => a b -> b  -- for parametric types (ie. Foo Float)


In addition, I'm having a hard time understanding the errors I'm getting from constructs like this:

data Foo a = Foo a 

class TwoPi a where
  div2pi :: (Floating b) => a -> b

instance (Floating a) => TwoPi (Foo a)  where
  div2pi (Foo x) = x / (2*pi)

{- only this code, no other instances in the file -}

It complains that I can't match expected b against inferred a where

      `b' is a rigid type variable bound by
          the type signature for `div2pi' at gcbTest.hs:6:22

which points immediately before the 'b' in (Floating b) of the div2pi type statement, and

      `a' is a rigid type variable bound by
          the instance declaration at gcbTest.hs:8:19

which points immediately before the 'a' in the (Floating a) of the instance definition.  It sounds like it's saying there's an explicit conflict between two type variables, both constrained identically.  Is the problem instead that they aren't well enough constrained?  It wants to know what instance of the Floating class to expect?  I would hope that it wouldn't care whether I provided Foo Float or Foo Double, and would return whatever type it received.

Here's the full error:

    Couldn't match expected type `b' against inferred type `a'
      `b' is a rigid type variable bound by
          the type signature for `div2pi' at gcbTest.hs:6:22
      `a' is a rigid type variable bound by
          the instance declaration at gcbTest.hs:8:19
    In the expression: x / (2 * pi)
    In the definition of `div2pi': div2pi (Foo x) = x / (2 * pi)
    In the instance declaration for `TwoPi (Foo a)'

Thanks--
  Greg


On Aug 27, 2010, at 02:31 AM, Jürgen Doser <jurgen.doser at gmail.com> wrote:

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


_______________________________________________
Beginners mailing list
Beginners at haskell.org
http://www.haskell.org/mailman/listinfo/beginners
-------------- next part --------------
Skipped content of type multipart/related


More information about the Beginners mailing list