Defining an instance: Syntax that works exactly sometimes

Dear Haskellers, The following compiles. (Rev stands for Reversible, and Dirn for Direction.) class Rev a where rev :: a -> a data Dirn = Succ | Pred deriving (Eq, Show, Ord) -- implement Ord (<=) Succ Pred = False (<=) _ _ = True -- implement Rev instance Rev Dirn where rev Succ = Pred rev Pred = Succ But if I try to define the Rev instance the same way the Ord instance is being defined, it does not compile: class Rev a where rev :: a -> a data Dirn = Succ | Pred deriving (Eq, Show, Ord, Rev) -- implement Ord, because Dirn is used as a key in a Map (<=) Succ Pred = False (<=) _ _ = True -- implement Rev rev Succ = Pred rev Pred = Succ What's going on? Many thanks, Jeff

In both cases, it's not actually creating a typeclass instance. However,
because (<=) from Ord is declared in GHC.Classes, you're able to create a
new (but completely unrelated) function named (<=). The fully qualified
names for these would be GHC.Classes.<= and YourModule.<=, so they don't
clash (but if you tried to use <= without qualifying it, you'd get an
ambiguous reference error).
In the case of Rev, you get an error, though, because both the class method
and the standalone function are declared in YourModule, which is illegal
(multiple declarations of the same name).
So, long story short, go with the "instance" syntax.
On Wed, Jan 21, 2015 at 7:23 PM, Jeffrey Brown
Dear Haskellers,
The following compiles. (Rev stands for Reversible, and Dirn for Direction.)
class Rev a where rev :: a -> a
data Dirn = Succ | Pred deriving (Eq, Show, Ord)
-- implement Ord (<=) Succ Pred = False (<=) _ _ = True
-- implement Rev instance Rev Dirn where rev Succ = Pred rev Pred = Succ
But if I try to define the Rev instance the same way the Ord instance is being defined, it does not compile:
class Rev a where rev :: a -> a
data Dirn = Succ | Pred deriving (Eq, Show, Ord, Rev)
-- implement Ord, because Dirn is used as a key in a Map (<=) Succ Pred = False (<=) _ _ = True
-- implement Rev rev Succ = Pred rev Pred = Succ
What's going on?
Many thanks, Jeff
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

On Wed, Jan 21, 2015 at 7:23 PM, Jeffrey Brown
The following compiles. (Rev stands for Reversible, and Dirn for Direction.)
class Rev a where rev :: a -> a
data Dirn = Succ | Pred deriving (Eq, Show, Ord)
-- implement Ord (<=) Succ Pred = False (<=) _ _ = True
You derived Ord; why are you doing this? You are locally overriding the Ord instance you derived with a (<=) that is *not* the one that is part of Ord.. and will therefore not contribute to the other functions from Ord. If you want to implement an instance manually, use the instance keyword. instance Ord Dim where (<=) Succ Pred = False (<=) _ _ = True The same applies to Rev later, but in that case it's redefining something defined in the same module and errors out. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

On Wed, Jan 21, 2015 at 7:48 PM, Michael Orlitzky
Insufficient keming on that font? =)
Probably... also half blind due to sinuses and the drugs trying to keep them at bay :/ -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

On 01/21/2015 07:50 PM, Brandon Allbery wrote:
On Wed, Jan 21, 2015 at 7:48 PM, Michael Orlitzky
mailto:michael@orlitzky.com> wrote: Insufficient keming on that font? =)
Probably... also half blind due to sinuses and the drugs trying to keep them at bay :/
I only noticed because I copy/pasted from your response and knew something was wrong but couldn't figure it out for a good 5 minutes.

On 01/21/2015 07:23 PM, Jeffrey Brown wrote:
data Dirn = Succ | Pred deriving (Eq, Show, Ord)
When you "derive" a typeclass instance, you get it magically for free. So you don't need to do this:
-- implement Ord (<=) Succ Pred = False (<=) _ _ = True
But if I try to define the Rev instance the same way the Ord instance is being defined, it does not compile:
... deriving (Eq, Show, Ord, Rev)
But you can't derive classes that you've defined yourself, it only works for predefined ones. (That's how the compiler can do it magically.) So "deriving (Rev)" won't work, because you made the "Rev" typeclass yourself. In the second case, you have to do: instance Rev Dirn where rev Succ = Pred rev Pred = Succ because you can't derive Rev, because it isn't a predefined typeclass. One more thing: when "deriving (Ord)", the compiler uses the order that you've typed the constructors in. So actually, the derived instance would have Succ <= Pred, probably not what you want. I'd switch it to "Pred | Succ" if I were you. The details of why all this failed in a confusing way have been explained in the other responses.

Jeffrey,
You didn't explain what you're trying to accomplish, and therefore folks
can only address the symptoms.
Here's what I'm seeing:
Suppose you have:
data A = A | B | C | D | E
You'd like a function that
given A returns E,
given B, returns D
given C, returns er, C
given D, returns B,
given E, returns A.
So you're hoping to write a Rev type class with singleton member
rev :: Rev a => a -> a
that would do the trick.
Thing is, you can already write a very generic
rev :: (Enum a, Bounded a) => a -> a
that would do the job.
Why is that sweet?
Because Enum + Bounded are auto-derivable for huge swathes of data types.
So you write the rev function (not type class instance!) once, and it'll
work for lots of your structures.
The best type class is often no type class. Especially when the compiler
isn't smart enough to read your mind. But I'm sure it's flattered you
thought so highly of it ;)
-- Kim-Ee
On Thu, Jan 22, 2015 at 7:23 AM, Jeffrey Brown
Dear Haskellers,
The following compiles. (Rev stands for Reversible, and Dirn for Direction.)
class Rev a where rev :: a -> a
data Dirn = Succ | Pred deriving (Eq, Show, Ord)
-- implement Ord (<=) Succ Pred = False (<=) _ _ = True
-- implement Rev instance Rev Dirn where rev Succ = Pred rev Pred = Succ
But if I try to define the Rev instance the same way the Ord instance is being defined, it does not compile:
class Rev a where rev :: a -> a
data Dirn = Succ | Pred deriving (Eq, Show, Ord, Rev)
-- implement Ord, because Dirn is used as a key in a Map (<=) Succ Pred = False (<=) _ _ = True
-- implement Rev rev Succ = Pred rev Pred = Succ
What's going on?
Many thanks, Jeff
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

Thank you, everybody. I had thought "deriving" and "instance" were just
different words for the same thing. Your answers were deeper than I am
currently capable of understanding.
I found instance declarations specified in 7.6.3 of The Glorious Glasgow
Haskell Compilation System User's Guide, Version 7.0.2:
https://downloads.haskell.org/~ghc/7.0.2/docs/html/users_guide/type-class-ex...
I have not found the "deriving" keyword's specification anywhere.
On Thu, Jan 22, 2015 at 8:57 AM, Kim-Ee Yeoh
Jeffrey,
You didn't explain what you're trying to accomplish, and therefore folks can only address the symptoms.
Here's what I'm seeing:
Suppose you have:
data A = A | B | C | D | E
You'd like a function that given A returns E, given B, returns D given C, returns er, C given D, returns B, given E, returns A.
So you're hoping to write a Rev type class with singleton member rev :: Rev a => a -> a that would do the trick.
Thing is, you can already write a very generic
rev :: (Enum a, Bounded a) => a -> a
that would do the job.
Why is that sweet?
Because Enum + Bounded are auto-derivable for huge swathes of data types. So you write the rev function (not type class instance!) once, and it'll work for lots of your structures.
The best type class is often no type class. Especially when the compiler isn't smart enough to read your mind. But I'm sure it's flattered you thought so highly of it ;)
-- Kim-Ee
On Thu, Jan 22, 2015 at 7:23 AM, Jeffrey Brown
wrote: Dear Haskellers,
The following compiles. (Rev stands for Reversible, and Dirn for Direction.)
class Rev a where rev :: a -> a
data Dirn = Succ | Pred deriving (Eq, Show, Ord)
-- implement Ord (<=) Succ Pred = False (<=) _ _ = True
-- implement Rev instance Rev Dirn where rev Succ = Pred rev Pred = Succ
But if I try to define the Rev instance the same way the Ord instance is being defined, it does not compile:
class Rev a where rev :: a -> a
data Dirn = Succ | Pred deriving (Eq, Show, Ord, Rev)
-- implement Ord, because Dirn is used as a key in a Map (<=) Succ Pred = False (<=) _ _ = True
-- implement Rev rev Succ = Pred rev Pred = Succ
What's going on?
Many thanks, Jeff
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

On Thu, Jan 22, 2015 at 10:34 PM, Jeffrey Brown
I have not found the "deriving" keyword's specification anywhere.
The correct place to look for this and other things, including instances, is the Haskell Report. https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-780004.... 4.3.3. Derived Instances https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-770004.... 4.3.2. Instance Declarations -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

Thanks (again) Brandon!
On Thu, Jan 22, 2015 at 7:40 PM, Brandon Allbery
On Thu, Jan 22, 2015 at 10:34 PM, Jeffrey Brown
wrote: I have not found the "deriving" keyword's specification anywhere.
The correct place to look for this and other things, including instances, is the Haskell Report.
https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-780004.... 4.3.3. Derived Instances
https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-770004.... 4.3.2. Instance Declarations
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

Should I always look first in the 98 Report, and only if I don't find
something there then look in the User's Guide? Should I always look through
both, lest something in the 98 Report be obsolete? Is nothing in it
obsolete?
On Thu, Jan 22, 2015 at 7:40 PM, Brandon Allbery
On Thu, Jan 22, 2015 at 10:34 PM, Jeffrey Brown
wrote: I have not found the "deriving" keyword's specification anywhere.
The correct place to look for this and other things, including instances, is the Haskell Report.
https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-780004.... 4.3.3. Derived Instances
https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-770004.... 4.3.2. Instance Declarations
-- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

On Fri, Jan 23, 2015 at 2:39 PM, Jeffrey Brown
Should I always look first in the 98 Report, and only if I don't find something there then look in the User's Guide? Should I always look through both, lest something in the 98 Report be obsolete? Is nothing in it obsolete?
You really want the 2010 report, not the 98 one. https://www.haskell.org/onlinereport/haskell2010/ You may first check the extensions part of the GHC manual: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghc-language... Usually extensions will be called out with a pragma, though, so if there are not {-# LANGUAGE #-} sections at the top then you probably don't need to check the GHC manual. If there are, look over the sections of the GHC manual relating to those LANGUAGE pragmas. -- brandon s allbery kf8nh sine nomine associates allbery.b@gmail.com ballbery@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net

On Fri, Jan 23, 2015, at 12:01 PM, Brandon Allbery wrote:
Usually extensions will be called out with a pragma
Unless you are looking at the source of a cabal package, in which case they might be centralized in the .cabal file. -Karl

Is anything in the 98 report obsolete?
The base language is remarkably stable. Haskell 2010 removed (n+k) pattern matching. And that's the only thing obsoleted over 12 years ! So it's all add, no removal. A better question to ask is, what's the 20% of the report that's used 80% of the time?
Should I always look first in the 98 Report, and only if I don't find something there then look in the User's Guide?
Sounds like a good plan. Over time, you'll understand what's haskell and what are ghc extensions. Humble advice: it's not enough to read the language def. You'll understand better by reading the conference proceedings that made the language what it is today. -- Kim-Ee
participants (6)
-
Brandon Allbery
-
Jeffrey Brown
-
Karl Voelker
-
Kim-Ee Yeoh
-
Michael Orlitzky
-
Ryan Trinkle