Inheritance and Wrappers

tldr: Can I make arbitrary instances of one class instantiate another without using wrappers? I'm new to Haskell, and am trying to implement some simple typeclasses for doing algebra. For example I have type class (simplified for the sake of argument) class AbGroup a where add :: a -> a -> a I would like any type instantiating Num to also be an abelian group: instance (Num a) => AbGroup a where add i j = i+j, but this doesn't compile because a is a variable, not a type constructor(or something). The problem is fixed, in a sense, If I introduce a wrapper class data Wrapper a = Wrap a instance (Num a) => AbGroup (Wrapper a) where add (Wrap i) (Wrap j) = Wrap(i+j) However, this is clumsy. Is there something else I can do? Thanks! -- View this message in context: http://haskell.1045720.n5.nabble.com/Inheritance-and-Wrappers-tp3365126p3365... Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

On 01/31/2011 08:58 PM, MattMan wrote:
[...]
data Wrapper a = Wrap a instance (Num a) => AbGroup (Wrapper a) where add (Wrap i) (Wrap j) = Wrap(i+j)
However, this is clumsy. Is there something else I can do? Thanks This is the normal approach. You can do funny things with the OverlappingInstances extension, but it is probably not what you want.
The problem is that the compiler only considers the heads of the instance declarations when determining which instance to use for a specific type. So an instance like this:
instance (Num a) => AbGroup a where ...
means: Some type matching 'a' (that is, any type) is an instance of 'AbGroup' if and only if it is an instance of 'Num'. An additional instance like
instance AbGroup SomeData where ...
would then conflict with the instance above: As 'SomeData' in particular matches the type 'a', the compiler does not know which one to choose. You could argue that the latter is "more specific" than the former, so the compiler should choose that one. This is exactly what OverlappingInstances does, but it can have more, unwanted effects. You can make your wrapper code less clumsy by deriving some instances such as
{-# LANGUAGE GeneralizedNewtypeDeriving #-} data Wrapper a = Wrap a deriving (Eq, Ord, Read, Show, Num)
-- Steffen

On Monday 31 January 2011 20:58:02, MattMan wrote:
tldr: Can I make arbitrary instances of one class instantiate another without using wrappers?
I'm new to Haskell, and am trying to implement some simple typeclasses for doing algebra. For example I have type class (simplified for the sake of argument)
class AbGroup a where add :: a -> a -> a
I would like any type instantiating Num to also be an abelian group:
instance (Num a) => AbGroup a where add i j = i+j,
but this doesn't compile because a is a variable, not a type constructor(or something). The problem is fixed, in a sense, If I introduce a wrapper class
data Wrapper a = Wrap a instance (Num a) => AbGroup (Wrapper a) where add (Wrap i) (Wrap j) = Wrap(i+j)
However, this is clumsy. Is there something else I can do? Thanks!
Not really. You could enable the FexibleInstances extension, then your first instance would compile. But it would mean 'every type is an instance of AbGroup, and if you try to use it with something that isn't also a Num, it won't compile, also you can't have any other instances', not what you want. You could then also enable OverlappingInstances, which would allow you to write other instances, but that extension is widely regarded as dangerous (have to confess, I forgot what the dangers were, one was that instance selection doesn't always do what you want/expect). Wrapper instances or specific instances are probably the best way (specific instances to be generated by a preprocessor or TH).

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 1/31/11 15:24 , Daniel Fischer wrote:
want. You could then also enable OverlappingInstances, which would allow you to write other instances, but that extension is widely regarded as dangerous (have to confess, I forgot what the dangers were, one was that instance selection doesn't always do what you want/expect).
Instance selection will still not look at the context, so multiple instances would complain about needing IncoherentInstances, and if you add *that* then it does something like taking the first matching instance it finds (again, ignoring the context completely). - -- brandon s. allbery [linux,solaris,freebsd,perl] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (Darwin) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk1HHNMACgkQIn7hlCsL25XFYgCgqLWUoZzYrZO54ydDY9kTa9RT 3VAAn0WgJzeWO5vvO4QP1pkEYL5tzxYB =+6Pz -----END PGP SIGNATURE-----

On Mon, 31 Jan 2011, Brandon S Allbery KF8NH wrote:
On 1/31/11 15:24 , Daniel Fischer wrote:
want. You could then also enable OverlappingInstances, which would allow you to write other instances, but that extension is widely regarded as dangerous (have to confess, I forgot what the dangers were, one was that instance selection doesn't always do what you want/expect).
Instance selection will still not look at the context, so multiple instances would complain about needing IncoherentInstances, and if you add *that* then it does something like taking the first matching instance it finds (again, ignoring the context completely).
Since the original poster classified himself as new to Haskell, I'm afraid that advanced and dangerous extensions are not the appropriate answer.

On Mon, 31 Jan 2011, MattMan wrote:
I'm new to Haskell, and am trying to implement some simple typeclasses for doing algebra. For example I have type class (simplified for the sake of argument)
class AbGroup a where add :: a -> a -> a
I would like any type instantiating Num to also be an abelian group:
instance (Num a) => AbGroup a where add i j = i+j,
If all methods of AbGroup can be defined for all Num types - why do you want an AbGroup at all? You could simply write functions with Num constraint. You may be also interested in existing approaches to algebra in Haskell: http://www.haskell.org/haskellwiki/Mathematical_prelude_discussion

<\quote> Henning Thielemann wrote:
If all methods of AbGroup can be defined for all Num types - why do you want an AbGroup at all? You could simply write functions with Num constraint.
Well, I'd rather not have to implement (*), abs, etc on every abelian group. You may be also interested in existing approaches to algebra in Haskell: http://www.haskell.org/haskellwiki/Mathematical_prelude_discussion Yes, in fact I am! Thanks for the suggestion; it seems "numeric-prelude" does [most of] the things I want. Thanks all. -- View this message in context: http://haskell.1045720.n5.nabble.com/Inheritance-and-Wrappers-tp3365126p3365... Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.
participants (5)
-
Brandon S Allbery KF8NH
-
Daniel Fischer
-
Henning Thielemann
-
MattMan
-
Steffen Schuldenzucker