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
*****************************************