Can multiple dispatch be achieved in Haskell with pattern matching on type classes? - haskell

This is a question about multiple dispatch in Haskell.
Below I use the term "compliant to [type class]" to mean "has type which is instance of [type class]", because type classes are often like interfaces, so it's intuitive to think of a concrete thing like an actual Int value as being "compliant" to an interface/type class by virtue of its type implementing whatever is needed to belong to that interface/type class.
Consider the example of wanting to make a single exponentiation function that will work whether it is called with Floating arguments, Num, Integral or whatever, and it works by using the type classes that are implemented by the types of the arguments to select a pre-existing exponentiation function to call.
The function (^) has type (^) :: (Integral b, Num a) => a -> b -> a and the function (**) has type (**) :: Floating a => a -> a -> a.
Suppose I want to create a function my_pow that accepts a Num compliant first argument and a Num compliant second argument.
If both arguments are Floating compliant, then it will call (**); if the second argument is merely Integral compliant, it will call (^); and any other case will give a pattern matching error.
My naive first try was to treat the type classes like value constructors and try to pattern match within the function definition:
my_pow :: (Num a, Num b) => a -> b -> a
my_pow (Floating x) (Floating y) = x ** y
my_pow x (Integral y) = x ^ y
but this gives the errors:
tmp.hs:25:6: Not in scope: data constructor `Floating'
tmp.hs:25:19: Not in scope: data constructor `Floating'
tmp.hs:26:8: Not in scope: data constructor `Integral'
probably meaning that I cannot treat type classes as value constructors, which is not surprising.
But then Googling around for how to pattern-match against particular type class properties of the arguments that are more specific than the type class constraints in the function definition did not yield any clear answers.
What is the preferred way to make this sort of polymorphism -- effectively a dispatch pattern where the function has relaxed type class constraints overall, but then is defined by pattern matching on more specific type class constraints for any of the cases it will dispatch to other other functions.

The normal way to "pattern match" on types in the way you're describing is with type class instances. With concrete types, this is easy using MultiParamTypeClasses; this is how Haskell implements multiple dispatch.
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, OverlappingInstances #-}
module SO26303353 where
class (Num a, Num b) => Power a b where
my_pow :: a -> b -> a
instance Power Double Double where
my_pow = (**)
instance Num a => Power a Integer where
my_pow = (^)
This works just fine. It's more or less idiomatic Haskell, except that (**) and (^) are different operations and some people might object to blurring the distinction.
You're asking for something a bit more elaborate, however. You want multiple dispatch not only on types but on classes of types. This is a significantly different and more powerful thing. In particular, it would work for all types that could have instances of Floating or Intergral, even types that haven't been written yet! Here's how it would be written ideally:
instance (Floating a) => Power a a where
my_pow = (**)
instance (Num a, Integral b) => Power a b where
my_pow = (^)
This doesn't work, though, because the constraint solver does not backtrack, and does not consider instance constraints when choosing an instance. So my_pow doesn't work, for instance, with two Ints:
ghci> :t my_pow :: Int -> Int -> Int
No instance for (Floating Int)
This happens because the "more specific" Power a a instance matches, because the two types are equal. GHC then imposes the Floating constraint on a, and barfs when it can't satisfy it. It does not then backtrack and try the Power a b instance.
It may or may not be possible to hack around the limitation using advanced type system features, but I don't think you could ever make a drop-in replacement for both (**) and (^) in current Haskell.
Edit: general comments
(Note that we're kind of straying away from a Q&A format here.)
In rereading your question and comment, I notice you're using the term "dispatch" in a way I'm not familiar with. A quick Google turns up articles on double dispatch and the visitor design pattern. Is that where you're coming from? They look a bit like what you're trying to do--write a function that does totally different things based on the types of its arguments. I want to add a few things to this answer that may help hone your sense of idiomatic Haskell. (Or may just be disjointed rambling.)
Haskell normally disregards the idea of a "runtime type". Even in #Cirdec's more elaborate answer, all the types are statically known, "at compile time." (Using the REPL, ghci, doesn't change things, except that "compile time" gets kind of hazy.) In fact, intuitions about what happen "at runtime" are often different in Haskell than other languages, not least because GHC performs aggressive optimizations.
Idiomatic Haskell is built on a foundation of parametric polymorphism; a function like replicate :: Int -> a -> [a] works absolutely the same for any type a. As a result, we know a lot about what replicate does without having to look at its implementation. This attitude is really helpful, and it deeply infects the brains of Haskell programmers. You'll notice that me and many other Haskell programmers go crazy with type annotations, especially in a forum like this one. The static types are very meaningful. (Keyword: free theorems.) (This isn't immediately relevant to your question.)
Haskell uses type classes to permit ad hoc polymorphism. In my mind, 'ad hoc' refers to the fact that the implementation of a function may be different for different types. This is of course critical for numerical types, and has been applied over the years in countless ways. But it's important to understand that everything is still statically typed, even with type classes. To actually evaluate any type-class function--to get a value out of it--you need to in the end choose a specific type. (With numeric types, the defaulting rules frequently choose it for you.) You can of course combine things to produce another polymorphic function (or value).
Historically, type classes were thought of strictly as a mechanism for function overloading, in the sense of having the same name for several distinct functions. In other words, rather than addInt :: Int -> Int -> Int, addFloat :: Float -> Float -> Float, we have one name: (+) :: Num a => a -> a -> a. But it's still fundamentally the same idea: there are a bunch of completely different functions called (+). (Now we tend to talk about type classes in terms of "laws," but that's a different topic.) There's oftentimes no literal dispatch occurring with a function like (+), or even non-primitive functions.
Yes, type classes are a bit like interfaces, but don't allow an OOP mindset to creep in too far. If you are writing a function with a type like Num a => a -> a, the expectation is that the only thing you know about a is that it is an instance of Num. You can't look behind the curtain, as it were. (Without cheating. Which is hard.) The only way to manipulate values of type a is with fully polymorphic functions and with other Num functions. In particular, you can't determine whether a is also an instance of some other class.
The various compiler extensions we've been playing with blur this model a bit, because we now can write, essentially, type level functions. But don't confuse that with dynamic dispatch.
Oh, by the way, Haskell does support dynamic types. See Data.Dymamic. To be honest, I've never really seen much use for it outside of interop with other languages. (I'm willing to be wrong.) The typical "visitor pattern" problems can be implemented in other ways.

Like Christian Conkle hinted at, we can determine if a type has an Integral or Floating instance using more advanced type system features. We will try to determine if the second argument has an Integral instance. Along the way we will use a host of language extensions, and still fall a bit short of our goal. I'll introduce the following language extensions where they are used
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverlappingInstances #-}
Convert Integral context to type
To begin with we will make a class that will try to capture information from the context of a type (whether there's an Integral instance) and convert it into a type which we can match on. This requires the FunctionalDependencies extension to say that the flag can be uniquely determined from the type a. It also requires MultiParamTypeClasses.
class IsIntegral a flag | a -> flag
We'll make two types to use for the flag type to represent when a type does (HTrue) or doesn't (HFalse) have an Integral instance. This uses the EmptyDataDecls extension.
data HTrue
data HFalse
We'll provide a default - when there isn't an IsIntegral instance for a that forces flag to be something other than HFalse we provide an instance that says it's HFalse. This requires the TypeFamilies, FlexibleInstances, and UndecidableInstances extensions.
instance (flag ~ HFalse) => IsIntegral a flag
What we'd really like to do is say that every a with an Integral a instance has an IsIntegral a HTrue instance. Unfortunately, if we add an instance (Integral a) => IsIntegral a HTrue instance we will be in the same situation Christian described. This second instance will be used by preference, and when the Integral constraint is encountered it will be added to the context with no backtracking. Instead we will need to list all the Integral types ourselves. This is where we fall short of our goal. (I'm skipping the base Integral types from System.Posix.Types since they aren't defined equally on all platforms).
import Data.Int
import Data.Word
import Foreign.C.Types
import Foreign.Ptr
instance IsIntegral Int HTrue
instance IsIntegral Int8 HTrue
instance IsIntegral Int16 HTrue
instance IsIntegral Int32 HTrue
instance IsIntegral Int64 HTrue
instance IsIntegral Integer HTrue
instance IsIntegral Word HTrue
instance IsIntegral Word8 HTrue
instance IsIntegral Word16 HTrue
instance IsIntegral Word32 HTrue
instance IsIntegral Word64 HTrue
instance IsIntegral CUIntMax HTrue
instance IsIntegral CIntMax HTrue
instance IsIntegral CUIntPtr HTrue
instance IsIntegral CIntPtr HTrue
instance IsIntegral CSigAtomic HTrue
instance IsIntegral CWchar HTrue
instance IsIntegral CSize HTrue
instance IsIntegral CPtrdiff HTrue
instance IsIntegral CULLong HTrue
instance IsIntegral CLLong HTrue
instance IsIntegral CULong HTrue
instance IsIntegral CLong HTrue
instance IsIntegral CUInt HTrue
instance IsIntegral CInt HTrue
instance IsIntegral CUShort HTrue
instance IsIntegral CShort HTrue
instance IsIntegral CUChar HTrue
instance IsIntegral CSChar HTrue
instance IsIntegral CChar HTrue
instance IsIntegral IntPtr HTrue
instance IsIntegral WordPtr HTrue
Matching on IsIntegral
Our end goal is to be able to provide appropriate instances for the following class
class (Num a, Num b) => Power a b where
pow :: a -> b -> a
We want to match on types to choose which code to use. We'll make a class with an extra type to hold the flag for whether b is an Integral type. The extra argument to pow' lets type inference choose the correct pow' to use.
class (Num a, Num b) => Power' flag a b where
pow' :: flag -> a -> b -> a
Now we'll write two instances, one for when b is Integral and one for when it isn't. When b isn't Integral, we can only provide an instance when a and b are the same.
instance (Num a, Integral b) => Power' HTrue a b where
pow' _ = (^)
instance (Floating a, a ~ b) => Power' HFalse a b where
pow' _ = (**)
Now, whenever we can determine if b is Integral with IsIntegral and can provide a Power' instance for that result, we can provide the Power instance which was our goal. This requires the ScopedTypeVariables extension to get the correct type for the extra argument to pow'
instance (IsIntegral b flag, Power' flag a b) => Power a b where
pow = pow' (undefined::flag)
Actually using these definitions requires the OverlappingInstances extension.
main = do
print (pow 7 (7 :: Int))
print (pow 8.3 (7 :: Int))
print (pow 1.2 (1.2 :: Double))
print (pow 7 (7 :: Double))
You can read another explanation of how to use FunctionalDependencies or TypeFamilies to avoid overlap in overlapping instances in the Advanced Overlap article on HaskellWiki.

Related

How to create a generic Complex type in haskell?

I want to create a Complex type to represent complex numbers.
Following works:
Prelude> data Complex = Complex Int Int
Prelude> :t Complex
Complex :: Int -> Int -> Complex
How can I change this to accept any Num type, instead of just Int.
I tried following:
Prelude> data Complex a = Num a => Complex a a
but got this:
* Data constructor `Complex' has existential type variables, a context, or a specialised result type
Complex :: forall a. Num a => a -> a -> Complex a
(Use ExistentialQuantification or GADTs to allow this)
* In the definition of data constructor `Complex'
In the data type declaration for `Complex'
I'm not really sure what to make of this error. Any help is appreciated.
Traditional data in Haskell is just that: data. It doesn't need to know anything about the properties of its fields, it just needs to be able to store them. Hence there's no real need to constrain the fields at that point; just make it
data Complex a = Complex !a !a
(! because strict fields are better for performance).
Of course when you then implement the Num instance, you will need a constraint:
instance (Num a) => Num (Complex a) where
fromInteger = (`Complex`0) . fromInteger
Complex r i + Complex ρ ι = Complex (r+ρ) (i+ι)
...
...in fact, you need the much stronger constraint RealFloat a to implement abs, at least that's how the standard version does it. (Which means, Complex Int is actually not usable, not with the standard Num hierarchy; you need e.g. Complex Double.)
That said, it is also possible to bake the constraint in to the data type itself. The ExistentialTypes syntax you tried is highly limiting though and not suitable for this; what you want instead is the GADT
data Complex a where
Complex :: Num a => a -> a -> Complex a
With that in place, you could then implement e.g. addition without mentioning any constraint in the signature
cplxAdd :: Complex a -> Complex a -> Complex a
cplxAdd (Complex r i) (Complex ρ ι) = Complex (r+ρ) (i+ι)
You would now need to fulfill Num whenever you try to construct a Complex value though. That means, you'd still need an explicit constraint in the Num instance.
Also, this version is potentially much slower, because the Num dictionary actually needs to be stored in the runtime representation.
Type constructors cannot be constrained in pure Haskell, only functions can. So it is supposed that you declare
data Complex a = Complex a a
and then constrain functions, like
conjugate :: (Num a) => Complex a -> Complex a
conjugate (Complex x y) = Complex x (-y)
In fact, the type and constraint for conjugate can be derived by the compiler, so you can just define the implementation:
conjugate (Complex x y) = Complex x (-y)
However, if you really wish to constrain the type constructor Complex, you can turn on some extensions that enable it, namely ExistentialQuantification or GADTs, as the compiler suggests. To do this, add this line to the very beginning of your file:
{-# LANGUAGE ExistentialQuantification #-}
or
{-# LANGUAGE GADTs #-}
Those are called pragmas.
While you could, as the compiler message instructs, use ExistentialQuantification, you could also define the type like this:
data Complex a = Complex a a deriving (Show, Eq)
It's a completely unconstrained type, so perhaps another name would be more appropriate... This type seems to often be called Pair...
When you write functions, however, you can constrain the values contained in the type:
myFunction :: Num a => Complex a -> a
myFunction (Complex x y) = x + y

Defining a Function for Multiple Types

How is a function defined for different types in Haskell?
Given
func :: Integral a => a -> a
func x = x
func' :: (RealFrac a , Integral b) => a -> b
func' x = truncate x
How could they be combined into one function with the signature
func :: (SomeClassForBoth a, Integral b) => a -> b
With a typeclass.
class TowardsZero a where towardsZero :: Integral b => a -> b
instance TowardsZero Int where towardsZero = fromIntegral
instance TowardsZero Double where towardsZero = truncate
-- and so on
Possibly a class with an associated type family constraint is closer to what you wrote (though perhaps not closer to what you had in mind):
{-# LANGUAGE TypeFamilies #-}
import GHC.Exts
class TowardsZero a where
type RetCon a b :: Constraint
towardsZero :: RetCon a b => a -> b
instance TowardsZero Int where
type RetCon Int b = Int ~ b
towardsZero = id
instance TowardsZero Double where
type RetCon Double b = Integral b
towardsZero = truncate
-- and so on
This is known as ad hoc polymorphism, where you execute different code depending on the type. The way this is done in Haskell is using typeclasses. The most direct way is to define a new class
class Truncable a where
trunc :: Integral b => a -> b
And then you can define several concrete instances.
instance Truncable Integer where trunc = fromInteger
instance Truncable Double where trunc = truncate
This is unsatisfying because it requires an instance for each concrete type, when there are really only two families of identical-looking instances. Unfortunately, this is one of the cases where it is hard to reduce boilerplate, for technical reasons (being able to define "instance families" like this interferes with the open-world assumption of typeclasses, among other difficulties with type inference). As a hint of the complexity, note that your definition assumes that there is no type that is both RealFrac and Integral, but this is not guaranteed -- which implementation should we pick in this case?
There is another issue with this typeclass solution, which is that the Integral version doesn't have the type
trunc :: Integral a => a -> a
as you specified, but rather
trunc :: (Integral a, Integral b) => a -> b
Semantically this is not a problem, as I don't believe it is possible to end up with some polymorphic code where you don't know whether the type you are working with is Integral, but you do need to know that when it is, the result type is the same as the incoming type. That is, I claim that whenever you would need the former rather than the latter signature, you already know enough to replace trunc by id in your source. (It's a gut feeling though, and I would love to be proven wrong, seems like a fun puzzle)
There may be performance implications, however, since you might unnecessarily call fromIntegral to convert a type to itself, and I think the way around this is to use {-# RULES #-} definitions, which is a dark scary bag of complexity that I've never really dug into, so I don't know how hard or easy this is.
I don't recommend this, but you can hack at it with a GADT:
data T a where
T1 :: a -> T a
T2 :: RealFrac a => a -> T b
func :: Integral a => T a -> a
func (T1 x) = x
func (T2 x) = truncate x
The T type says, "Either you already know the type of the value I'm wrapping up, or it's some unknown instance of RealFrac". The T2 constructor existentially quantifies a and packs up a RealFrac dictionary, which we use in the second clause of func to convert from (unknown) a to b. Then, in func, I'm applying an Integral constraint to the a which may or may not be inside the T.

Resolving type ambiguities using available class instances

Given the following code:
import Data.Word
data T = T deriving (Eq, Show)
class C a where f :: a -> ()
instance C T where f _ = ()
instance C Word16 where f _ = ()
main = return $ f 0x16
GHC complains that it can't infer what the type for the literal 0x16 should be with the error:
No instance for (Num a0) arising from the literal ‘22’
The type variable ‘a0’ is ambiguous
It is easy to see why this would be -- Haskell allows numeric literals to be of any type which has an instance of Num, and here we can't disambiguate what the type for the literal 0x16 (or 22) should be.
It's also clear as a human reading this what I intended to do -- there is only one available instance of the class C which satisfies the Num constraint, so obviously I intended to use that one so 0x16 should be treated as a Word16.
There are two ways that I know to fix it: Either annotate the literal with its type:
main = return $ f (0x16 :: Word16)
or define a function which essentially does that annotation for you:
w16 x = x :: Word16
main = return $ f (w16 0x16)
I have tried a third way, sticking default (Word16) at the top of the file in the hope that Haskell would pick that as the default type for numeric literals, but I guess I'm misunderstanding what the default keyword is supposed to do because that didn't work.
I understand that typeclasses are open, so just because you can make the assumption in the context quoted above that Word16 is the only numeric instance of C that may not hold in some other module. But my question is: is there some mechanism by which I can assume/enforce that property, so that it is possible to use f and have Haskell resolve the type of its numeric argument to Word16 without explicit annotations at the call site?
The context is that I am implementing an EDSL, and I would rather not have to include manual type hints when I know that my parameters will either be Word16 or some other non-numeric type. I am open to a bit of dirty types/extensions abuse if it makes the EDSL feel more natural! Although if solutions do involve the naughty pragmas I'd definitely appreciate hints on what I should be wary about when using them.
Quick solution with "naughty pragmas" with GHC 7.10:
{-# LANGUAGE TypeFamilies, FlexibleInstances #-}
class C a where f :: a -> ()
instance C T where f _ = ()
instance {-# INCOHERENT #-} (w ~ Word16) => C w where f _ = ()
And with GHC 7.8:
{-# LANGUAGE TypeFamilies, FlexibleInstances, IncoherentInstances #-}
class C a where f :: a -> ()
instance C T where f _ = ()
instance (w ~ Word16) => C w where f _ = ()
Here, GHC essentially picks an arbitrary most specific instance that remains after trying to unify the instances heads and constraints.
You should only use this if
You have a fixed set of instances and don't export the class.
For all use cases of the class method, there is a single possible most specific instance (given the constraints).
Many people advise against ever using IncoherentInstances, but I think it can be quite fun for DSL-s, if we observe the above considerations.
For anybody else wondering about default (I know I was!)
https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-750004.3
Quoting section 4.3.4:
In situations where an ambiguous type is discovered, an ambiguous type variable, v, is defaultable if:
v appears only in constraints of the form C v, where C is a class, and
at least one of these classes is a numeric class, (that is, Num or a subclass of Num), and
all of these classes are defined in the Prelude or a standard library.
So that explains why your default clause is being completely ignored; C is not a standard library type-class.
(As to why this is the rule… can't help you there. Presumably to avoid breaking arbitrary user-defined code.)

Associated Parameter Restriction using Functional Dependency

The function f below, for a given type 'a', takes a parameter of type 'c'. For different types 'a', 'c' is restricted in different ways. Concretely, when 'a' is any Integral type, 'c' should be allowed to be any 'Real' type. When 'a' is Float, 'c' can ONLY be Float.
One attempt is:
{-# LANGUAGE
MultiParamTypeClasses,
FlexibleInstances,
FunctionalDependencies,
UndecidableInstances #-}
class AllowedParamType a c | a -> c
class Foo a where
f :: (AllowedParamType a c) => c -> a
fIntegral :: (Integral a, Real c) => c -> a
fIntegral = error "implementation elided"
instance (Integral i, AllowedParamType i d, Real d) => Foo i where
f = fIntegral
For some reason, GHC 7.4.1 complains that it "could not deduce (Real c) arising from a use of fIntegral". It seems to me that the functional dependency should allow this deduction. In the instance, a is unified with i, so by the functional dependency, d should be unified with c, which in the instance is declared to be 'Real'. What am I missing here?
Functional dependencies aside, will this approach be expressive enough to enforce the restrictions above, or is there a better way? We are only working with a few different values for 'a', so there will be instances like:
instance (Integral i, Real c) => AllowedParamType i c
instance AllowedParamType Float Float
Thanks
A possibly better way, is to use constraint kinds and type families (GHC extensions, requires GHC 7.4, I think). This allows you to specify the constraint as part of the class instance.
{-# LANGUAGE ConstraintKinds, TypeFamilies, FlexibleInstances, UndecidableInstances #-}
import GHC.Exts (Constraint)
class Foo a where
type ParamConstraint a b :: Constraint
f :: ParamConstraint a b => b -> a
instance Integral i => Foo i where
type ParamConstraint i b = Real b
f = fIntegral
EDIT: Upon further experimentation, there are some subtleties that mean that this doesn't work as expected, specifically, type ParamConstraint i b = Real b is too general. I don't know a solution (or if one exists) right now.
OK, this one's been nagging at me. given the wide variety of instances,
let's go the whole hog and get rid of any relationship between the
source and target type other than the presence of an instance:
{-# LANGUAGE OverlappingInstances, FlexibleInstances,TypeSynonymInstances,MultiParamTypeClasses #-}
class Foo a b where f :: a -> b
Now we can match up pairs of types with an f between them however we like, for example:
instance Foo Int Int where f = (+1)
instance Foo Int Integer where f = toInteger.((7::Int) -)
instance Foo Integer Int where f = fromInteger.(^ (2::Integer))
instance Foo Integer Integer where f = (*100)
instance Foo Char Char where f = id
instance Foo Char String where f = (:[]) -- requires TypeSynonymInstances
instance (Foo a b,Functor f) => Foo (f a) (f b) where f = fmap f -- requires FlexibleInstances
instance Foo Float Int where f = round
instance Foo Integer Char where f n = head $ show n
This does mean a lot of explicit type annotation to avoid No instance for... and Ambiguous type error messages.
For example, you can't do main = print (f 6), but you can do main = print (f (6::Int)::Int)
You could list all of the instances with the standard types that you want,
which could lead to an awful lot of repetition, our you could light the blue touchpaper and do:
instance Integral i => Foo Double i where f = round -- requires FlexibleInstances
instance Real r => Foo Integer r where f = fromInteger -- requires FlexibleInstances
Beware: this does not mean "Hey, if you've got an integral type i,
you can have an instance Foo Double i for free using this handy round function",
it means: "every time you have any type i, it's definitely an instance
Foo Double i. By the way, I'm using round for this, so unless your type i is Integral,
we're going to fall out." That's a big issue for the Foo Integer Char instance, for example.
This can easily break your other instances, so if you now type f (5::Integer) :: Integer you get
Overlapping instances for Foo Integer Integer
arising from a use of `f'
Matching instances:
instance Foo Integer Integer
instance Real r => Foo Integer r
You can change your pragmas to include OverlappingInstances:
{-# LANGUAGE OverlappingInstances, FlexibleInstances,TypeSynonymInstances,MultiParamTypeClasses #-}
So now f (5::Integer) :: Integer returns 500, so clearly it's using the more specific Foo Integer Integer instance.
I think this sort of approach might work for you, defining many instances by hand, carefully considering when to go completely wild
making instances out of standard type classes. (Alternatively, there aren't all that many standard types, and as we all know, notMany choose 2 = notIntractablyMany, so you could just list them all.)
Here's a suggestion to solve a more general problem, not yours specifically (I need more detail yet first - I promise to check later). I'm writing it in case other people are searching for a solution to a similar problem to you, I certainly was in the past, before I discovered SO. SO is especially great when it helps you try a radically new approach.
I used to have the work habit:
Introduce a multi-parameter type class (Types hanging out all over the place, so...)
Introduce functional dependencies (Should tidy it up but then I end up needing...)
Add FlexibleInstances (Alarm bells start ringing. There's a reason the compiler has this off by default...)
Add UndecidableInstances (GHC is telling you you're on your own, because it's not convinced it's up to the challenge you're setting it.)
Everything blows up. Refactor somehow.
Then I discovered the joys of type families (functional programming for types (hooray) - multi-parameter type classes are (a bit like) logic programming for types). My workflow changed to:
Introduce a type class including an associated type, i.e. replace
class MyProblematicClass a b | a -> b where
thing :: a -> b
thang :: b -> a -> b
with
class MyJustWorksClass a where
type Thing a :: * -- Thing a is a type (*), not a type constructor (* -> *)
thing :: a -> Thing a
thang :: Thing a -> a -> Thing a
Nervously add FlexibleInstances. Nothing goes wrong at all.
Sometimes fix things by using constraints like (MyJustWorksClass j,j~a)=> instead of (MyJustWorksClass a)=> or (Show t,t ~ Thing a,...)=> instead of (Show (Thing a),...) => to help ghc out. (~ essentially means 'is the same type as')
Nervously add FlexibleContexts. Nothing goes wrong at all.
Everything works.
The reason "Nothing goes wrong at all" is that ghc calculates the type Thing a using my type function Thang rather than trying to deduce it using a merely a bunch of assertions that there's a function there and it ought to be able to work it out.
Give it a go! Read Fun with Type Functions before reading the manual!

Haskell Typeclass shorthand

So, I have a pair of typeclasses that I'll be using a lot together, and I want to avoid specifying both each time. Basically, instead of putting
:: (Ord a, Fractional a, Ord b, Fractional b, ... Ord z, Fractional z) =>
at the beginning of all my type specifications, I'd rather put
:: (OrdFractional a, OrdFractional b, ... OrdFractional z)
So, my initial idea on how to do this was to just declare a new typeclass
module Example where
class (Fractional a, Ord a) => OrdFractional a
example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool
example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3)
But this didn't work as automagically as I wished it would:
% ghci
Prelude> :l Example.hs
Ok, modules loaded: Example.
Prelude Example> example (1::Float,3::Float) (2,2) (3,1)
<interactive>:1:0:
No instance for (OrdFractional Float)
arising from a use of `example' at <interactive>:1:0-39
Possible fix:
add an instance declaration for (OrdFractional Float)
In the expression: example (1 :: Float, 3 :: Float) (2, 2) (3, 1)
In the definition of `it':
it = example (1 :: Float, 3 :: Float) (2, 2) (3, 1)
Manually creating instances seems like a drag so, next, I thought I might try to automatically create instances:
module Example where
class OrdFractional a
instance (Fractional a, Ord a) => OrdFractional a
example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool
example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3)
But the compiler didn't like that:
ghc -c Example.hs
Example.hs:4:0:
Illegal instance declaration for `OrdFractional a'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are type *variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `OrdFractional a'
So is there a way I can do this?
With the ConstraintKinds extension introduced in GHC 7.4, constraints are now types of kind Constraint, so you can use ordinary type synonyms to get what you want:
{-# LANGUAGE ConstraintKinds #-}
type OrdFractional a = (Ord a, Fractional a)
What you want is a class alias. There is a proposal to add it to Haskell at http://repetae.net/recent/out/classalias.html
When the compiler says "Use -XFlexibleInstances", you should try adding
{-# LANGUAGE FlexibleInstances #-}
to the top of your source (and go read the documentation to learn what it does, of course!).
In this specific case, this will make your code work:
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
Flexible instances are required in order to enable the => context on the instance head, and undecidable instances are required because the compiler, when handling an OrdFractional a context, can end adding Fractional a and Ord a to the context -- which doesn't directly help with finally determining a, and under suitably horrible circumstances, typechecking may diverge; the compiler really doesn't like that. (You probably wouldn't like it if the compiler went on forever or ran out of memory, either.)
No.
Your solution of a superclass implying the other classes is the closest to what you want that is possible in Haskell. Even though that requires manual instances of that new class it is sometimes used, for example in the rewriting library.
As CesarB mentioned class aliases do what you want (and more), but they're just a proposal that's been around for years now and have never been implemented, probably because there are numerous problems with it. Instead, various other proposals have popped up, but none of those were implemented either. (For a list of those proposals, see this Haskellwiki page.) One of the projects at Hac5 was to modify the GHC to include a small subset of class aliases called context synonyms (which do exactly what you are asking for here and nothing more), but sadly it was never finished.

Resources