Send Beginners mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        http://www.haskell.org/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
        [email protected]

You can reach the person managing the list at
        [email protected]

When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."


Today's Topics:

   1. Re:  typeclass confusion (Tobias Brandt)
   2. Re:  typeclass confusion (Isaac Dupree)
   3. Re:  typeclass confusion (Greg Best)
   4. Re:  typeclass confusion (Greg Best)


----------------------------------------------------------------------

Message: 1
Date: Tue, 24 Aug 2010 05:06:05 +0200
From: Tobias Brandt <[email protected]>
Subject: Re: [Haskell-beginners] typeclass confusion
To: Greg <[email protected]>
Cc: [email protected]
Message-ID:
        <[email protected]>
Content-Type: text/plain; charset="iso-8859-1"

You don't need a type class, you can just define your functions with pattern
matching:

rad :: Angle a -> a
rad (Radians x) = x
rad (Degrees x) = pi * (deg x) / 180

deg :: Angle a -> a
deg (Radians x) = 180 * (rad x) / pi
deg (Degrees x) = x

Alternatively, you can define Radians and Degrees as separate types and use
a type class:

data Radians a = Radians a
data Degrees a = Degrees a

class Angular a where
    rad :: a b -> b
    deg :: a b -> b

instance Angular Radians where
    rad (Radians x) = x
    deg (Radians x) = 180 * (rad x) / pi

instance Angular Degrees where
    rad (Degrees x) = pi * (deg x) / 180
    deg (Degrees x) = x

This would be extensible, but it this case not really useful.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: 
http://www.haskell.org/pipermail/beginners/attachments/20100823/e24a6c00/attachment-0001.html

------------------------------

Message: 2
Date: Tue, 24 Aug 2010 01:01:38 -0400
From: Isaac Dupree <[email protected]>
Subject: Re: [Haskell-beginners] typeclass confusion
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed

On 08/23/10 22:33, Greg wrote:
> ...it would be nice to force
> the type system to check whether I'm using degrees or radians:
>
> data Angle a = Radians a
> | Degrees a
> deriving (Eq, Show)

You did it wrong... the difference between Radians and Degrees here is 
only visible at runtime, as they are both of the same type, Angle. 
Don't feel bad, this confused me for a while as a Haskell-beginner too. 
  An example to "force the type system to check" would be

data Radians a = Radians a  deriving (Eq, Show)
data Degrees a = Degrees a  deriving (Eq, Show)

Then you could make conversion functions, say,
radToDeg :: (Floating a) => Radians a -> Degrees a
degToRad :: (Floating a) => Degrees a -> Radians a

and implement them;

you *could* have a 'class Angle' or such, if you wanted... perhaps trig 
functions or such would be sensible to put in there.  And/or you could 
try to make each data-type be a member of Num and related classes (being 
able to add angles, etc)

For a real program, I think I would try to stick to just one unit (e.g. 
radians) for internal program use (and convert any outside data to that 
unit promptly), unless there was a reason that didn't work very well; 
but the typeclass-stuff is an excellent thing to play with!

-Isaac


------------------------------

Message: 3
Date: Mon, 23 Aug 2010 22:10:30 -0700
From: Greg Best <[email protected]>
Subject: Re: [Haskell-beginners] typeclass confusion
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset="us-ascii"

Thank you!  I agree that what I'm doing isn't useful from an application 
perspective, but this turned out to be very useful for comprehension.

It was the 

rad :: a b -> b

that I was missing.  Two type variables-- one for Angle and one for Float.  
This now compiles just fine:

data Angle a = Radians a
             | Degrees a
             deriving (Eq, Show)

class Angular a where
  rad :: (Floating b) => a b -> b
  rad x = pi * (deg x) / 180
  deg :: (Floating b) => a b -> b
  deg x = 180 * (rad x) / pi

instance Angular Angle where
    rad (Radians x) = x
    deg (Degrees x) = x 

x :: Angle Float
x = Radians (pi / 2)

y :: Float
y  = deg x

It just doesn't execute, because of a non-exhaustive pattern for deg.  I guess 
that makes sense-- the default functions are per type, not per value 
constructor...

Changing my instance definition to this:

instance Angular Angle where
    rad (Radians x) = x
    rad (Degrees x) = pi * x / 180
    deg (Radians x) = 180 * x / pi
    deg (Degrees x) = x 

resolves the problem.

Thanks again for the help.  I'm now that much further down the type system 
learning curve...

Cheers--
 Greg


On Aug 23, 2010, at 8:06 PM, Tobias Brandt wrote:

> You don't need a type class, you can just define your functions with pattern 
> matching:
> 
> rad :: Angle a -> a
> rad (Radians x) = x
> rad (Degrees x) = pi * (deg x) / 180
> 
> deg :: Angle a -> a
> deg (Radians x) = 180 * (rad x) / pi
> deg (Degrees x) = x
> 
> Alternatively, you can define Radians and Degrees as separate types and use a 
> type class:
> 
> data Radians a = Radians a
> data Degrees a = Degrees a
> 
> class Angular a where
>     rad :: a b -> b
>     deg :: a b -> b
> 
> instance Angular Radians where
>     rad (Radians x) = x
>     deg (Radians x) = 180 * (rad x) / pi
> 
> instance Angular Degrees where
>     rad (Degrees x) = pi * (deg x) / 180
>     deg (Degrees x) = x
> 
> This would be extensible, but it this case not really useful.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: 
http://www.haskell.org/pipermail/beginners/attachments/20100824/1ec0a248/attachment-0001.html

------------------------------

Message: 4
Date: Mon, 23 Aug 2010 22:38:59 -0700
From: Greg Best <[email protected]>
Subject: Re: [Haskell-beginners] typeclass confusion
To: [email protected]
Message-ID: <[email protected]>
Content-Type: text/plain; charset=us-ascii

[hopefully this won't double post, I accidentally sent from a non-member 
address]

Thanks.  I wasn't trying to do anything terribly practical-- just looking for 
toy problems to get my head around the type system.

The part I figured was impractical was the "Angular" class, but this is the 
second feedback that suggested making both Degrees and Radians type 
constructors rather than alternate value constructors.  Is that the right 
approach?  I know the trig functions are already available and they all just 
traffic in floats, but if this weren't the case, I'd imagine a structure along 
the lines of

data Angle a = Radians a
            | Degrees a
            deriving (Eq, Show)

sin :: Angle a -> a

I think the approach you were suggesting is to make Degrees and Radians as 
types, and put sin as a function of the class.  I suppose that is better in 
that it makes it much easier to implement additional angular measurements 
(without reimplementing sin).

My reservations were with needing to define sin for each angle type (which I 
now think my method would force me to do anyway), which could be a potentially 
expensive operation.  With Degree and Radian as types, I think I can get away 
without reimplementing by using default functions such as:

sin x = radianSin $ rad x

or some such which would only require that I define a radian conversion for 
each angle type.

(where Degree and Radian are stand ins for useful types and classes)

Cheers--
Greg

On Aug 23, 2010, at 10:01 PM, Isaac Dupree wrote:

> On 08/23/10 22:33, Greg wrote:
>> ...it would be nice to force
>> the type system to check whether I'm using degrees or radians:
>> 
>> data Angle a = Radians a
>> | Degrees a
>> deriving (Eq, Show)
> 
> You did it wrong... the difference between Radians and Degrees here is only 
> visible at runtime, as they are both of the same type, Angle. Don't feel bad, 
> this confused me for a while as a Haskell-beginner too.  An example to "force 
> the type system to check" would be
> 
> data Radians a = Radians a  deriving (Eq, Show)
> data Degrees a = Degrees a  deriving (Eq, Show)
> 
> Then you could make conversion functions, say,
> radToDeg :: (Floating a) => Radians a -> Degrees a
> degToRad :: (Floating a) => Degrees a -> Radians a
> 
> and implement them;
> 
> you *could* have a 'class Angle' or such, if you wanted... perhaps trig 
> functions or such would be sensible to put in there.  And/or you could try to 
> make each data-type be a member of Num and related classes (being able to add 
> angles, etc)
> 
> For a real program, I think I would try to stick to just one unit (e.g. 
> radians) for internal program use (and convert any outside data to that unit 
> promptly), unless there was a reason that didn't work very well; but the 
> typeclass-stuff is an excellent thing to play with!
> 
> -Isaac
> _______________________________________________
> Beginners mailing list
> [email protected]
> http://www.haskell.org/mailman/listinfo/beginners



------------------------------

_______________________________________________
Beginners mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/beginners


End of Beginners Digest, Vol 26, Issue 47
*****************************************

Reply via email to