How to handle functions of a multi-parameter typeclass, who not need every type of the typeclass? - haskell

I've defined a typeclass similar to an interface with a bunch of functions required for my program. Sadly, it needs multiple polymorphic types, but not every function of this multi-parameter typeclass needs every type. GHC haunts me with undeduceable types and i can't get the code running.
A reduced example:
{-# LANGUAGE MultiParamTypeClasses #-}
class Foo a b where
-- ...
bar :: a -> ()
baz :: Foo a b => a -> ()
baz = bar
GHC says
Possible fix: add a type signature that fixes these type variable(s)
How can I do this for b? Especially when I want to keep b polymorphic. Only an instance of Foo should define what this type is.

This is impossible.
The underlying problem is that a multiparameter type class depends on every type parameter. If a particular definition in the class doesn't use every type parameter, the compiler will never be able to know what instance you mean, and you'll never even be able to specify it. Consider the following example:
class Foo a b where
bar :: String -> IO a
instance Foo Int Char where
bar x = return $ read x
instance Foo Int () where
bar x = read <$> readFile x
Those two instances do entirely different things with their parameter. The only way the compiler has to select one of those instances is matching both type parameters. But there's no way to specify what the type parameter is. The class is just plain broken. There's no way to ever call the bar function, because you can never provide enough information for the compiler to resolve the class instance to use.
So why is the class definition not rejected by the compiler? Because you can sometimes make it work, with the FunctionalDependencies extension.
If a class has multiple parameters, but they're related, that information can sometimes be added to the definition of the class in a way that allows a class member to not use every type variable in the class's definition.
class Foo a b | a -> b where
bar :: String -> IO a
With that definition (which requires the FunctionalDependencies extension), you are telling the compiler that for any particular choice of a, there is only one valid choice of b. Attempting to even define both of the above instances would be a compile error.
Given that, the compiler knows that it can select the instance of Foo to use based only on the type a. In that case, bar can be called.

Splitting it in smaller typeclasses might be sufficient.
{-# LANGUAGE MultiParamTypeClasses #-}
class Fo a => Foo a b where
-- ...
foo :: a -> b -> ()
class Fo a where
bar :: a -> ()
baz :: Foo a b => a -> ()
baz = bar

Assuming you really want to use more than one instance for a given a (and so cannot use functional dependencies as others mentioned), one possibility which may or may not be right for you is to use a newtype tagged with a "phantom" type used only to guide type selection. This compiles:
{-# LANGUAGE MultiParamTypeClasses #-}
newtype Tagged t a = Tagged { unTagged :: a } -- Also defined in the tagged package
-- on Hackage
class Foo a b where
bar :: Tagged b a -> ()
baz :: Foo a b => Tagged b a -> ()
baz = bar
Then you will be able to wrap your values in such a way that you can give an explicit type annotation to select the right instance.

Another way of refactoring multi-parameter type classes when they get awkward is to use the TypeFamilies extension. Like FunctionalDependencies, this works well when you can reframe your class as having only a single parameter (or at least, fewer parameter), with the other types that are different from instance to instance being computed from the actual class parameters.
Generally I've found whenever I thought I needed a multi-parameter type class, the parameters almost always varied together rather than varying independently. In this situation it's much easier to pick one as "primary" and use some system for determining the others from it. Functional dependencies can do this as well as type families, but many find type families a lot easier to understand.
Here's an example:
{-# LANGUAGE TypeFamilies, FlexibleInstances #-}
class Glue a where
type Glued a
glue :: a -> a -> Glued a
instance Glue Char where
type Glued Char = String
glue x y = [x, y]
instance Glue String where
type Glued String = String
glue x y = x ++ y
glueBothWays :: Glue a => a -> a -> (Glued a, Glued a)
glueBothWays x y = (glue x y, glue y x)
The above declares a class Glue of types that can be glued together with the glue operation, and that have a corresponding type which is the result of the "gluing".
I then declared a couple of instances; Glued Char is String, Glued String is also just String.
Finally I wrote a function to show how you use Glued when you're being polymorphic over the instance of Glue you're using; basically you "call" Glued as a function in your type signatures; this means glueBothWays doesn't "know" what type Glued a is, but it knows how it corresponds to a. You can even use Glued Char as a type, if you know you're gluing Chars but don't want to hard-code the assumption that Glued Char = String.

Related

Is there a way to refer directly to typeclass instances in Haskell?

The benefit of this could be to store certain metadata about the type in a canonical location. Sometimes, it isn't convenient to have a value of the type before using some instance methods on it; For instance if I have:
class Foo a where
foo :: String
foo = "Foo"
This is not actually valid Haskell. Instead it seems I have to have something like:
class Foo a where
foo :: a -> String
foo = const "Foo"
and now foo will actually have type Foo a => a -> String, but I would actually like to be able to do something like having a foo with type Instance Foo -> String. For this to be useful in some contexts, it might be also necessary to iterate over all (in-scope?) instances, or in other contexts, to be able to specifically materialize an instance for a given type.
I guess the issue is that instances and typeclasses are not first-class entities in Haskell?
The "old school" way of doing it is providing a "dummy" parameter whose purpose is nothing but helping the compiler find the appropriate instance. In this world, your class would look something like:
data Dummy a = Dummy
class Foo a where
foo :: Dummy a -> String
-- usage:
boolFoo = foo (Dummy :: Dummy Bool)
In fact, this trick was so ubiquitous that the Dummy type was semi-standardized as Data.Proxy.
But in modern GHC there is a better way: TypeApplications.
With this extension enabled, you can just straight up specify the type when calling the class method:
class Foo a where
foo :: String
boolFoo = foo #Bool
(this doesn't only work for class methods; it will work with any generic function, but be careful with the order of type parameters!)
You may also need to enable AllowAmbiguousTypes in order to declare such class. Though I'm not sure I remember this correctly, and I don't have a computer handy to check.
The old way (which I still prefer) is to use a proxy.
import Data.Proxy
class Foo a where
foo :: Proxy a -> String
instance Foo FancyPants where
foo _ = "a fancypants instance"
fooString :: String
fooString = foo (Proxy :: Proxy FancyPants)
So we didn't actually need a value of type FancyPants to use foo, all we needed is a value of Proxy FancyPants -- but you can create proxies of any type you want. This can be done in a polymorphic context too; usually it requires the use of the ScopedTypeVariables extension.
The new way is to use the TypeApplications and AllowAmbiguousTypes extension:
{-# LANGUAGE TypeApplications, AllowAmbiguousTypes #-}
class Foo a where
foo :: String
instance Foo FancyPants where
foo = "a fancypants instance"
fooString :: String
fooString = foo #FancyPants
Which looks nicer, but working with it in practice tends to be more irritating for a reason I can't quite put my finger on.
Did that answer the question?

How to declare instances of a typeclass (like Show) for all types in my own typeclass?

I have a typeclass:
class Wrapper w where
open :: w -> Map String Int
close :: Map String Int -> w
It doesn't look very useful, but I use it to strongly (not just a type synonym) distinguish between semantically different varieties of Map String Ints:
newtype FlapMap = Flap (Map String Int)
newtype SnapMap = Snap (Map String Int)
...
and still have functions that operate on any type of the class.
Is there a better way to do this distinction (maybe without the Wrapper instances boilerplate)?
I want to do this:
instance (Wrapper wrapper) => Show wrapper where
show w = show $ toList $ open w
instead of writing many boilerplate Show instances as well.
Via FlexibleInstances and UndecidableInstances, GHC leads me to a point where it thinks my instance declaration applies to everything, as it allegedly clashes with the other Show instances in my code and in GHC.Show. HaskellWiki and StackOverflow answerers and HaskellWiki convince me OverlappingInstances is not quite safe and possibly confusing. GHC doesn't even suggest it.
Why does GHC first complain about not knowing which instance of fx Show Int to pick (so why it doesn't look at the constraint I give at compile time?) and then, being told that instances may overlap, suddenly know what to do?
Can I avoid allowing OverlappingInstances with my newtypes?
You can’t do this without OverlappingInstances, which as you mention, is unpredictable. It won’t help you here, anyway, so you pretty much can’t do this at all without a wrapper type.
That’s rather unsatisfying, of course, so why is this the case? As you’ve already determined, GHC does not look at the instance context when picking an instance, only the instance head. Why? Well, consider the following code:
class Foo a where
fooToString :: a -> String
class Bar a where
barToString :: a -> String
data Something = Something
instance Foo Something where
fooToString _ = "foo something"
instance Bar Something where
barToString _ = "bar something"
instance Foo a => Show a where
show = fooToString
instance Bar a => Show a where
show = barToString
If you consider the Foo or Bar typeclasses in isolation, the above definitions make sense. Anything that implements the Foo typeclass should get a Show instance “for free”. Unfortunately, the same is true of the Bar instance, so now you have two valid instances for show Something.
Since typeclasses are always open (and indeed, Show must be open if you are able to define your own instances for it), it’s impossible to know that someone will not come along and add their own similar instance, then create an instance on your datatype, creating ambiguity. This is effectively the classic diamond problem from OO multiple inheritance in typeclass form.
The best you can get is to create a wrapper type that provides the relevant instances:
{-# LANGUAGE ExistentialQuantification #-}
data ShowableWrapper = forall w. Wrapper w => ShowableWrapper w
instance Show ShowableWrapper where
show (ShowableWrapper w) = show . toList $ open w
At that point, though, you really aren’t getting much of an advantage over just writing your own showWrapper :: Wrapper w => w -> String function.

How can I make my type an instance of Arbitrary?

I have the following data and function
data Foo = A | B deriving (Show)
foolist :: Maybe Foo -> [Foo]
foolist Nothing = [A]
foolist (Just x) = [x]
prop_foolist x = (length (foolist x)) == 1
when running quickCheck prop_foolist, ghc tells me that Foo needs to be an instance of Arbitrary.
No instance for (Arbitrary Foo) arising from a use of ‘quickCheck’
In the expression: quickCheck prop_foolist
In an equation for ‘it’: it = quickCheck prop_foolist
I tried data Foo = A | B deriving (Show, Arbitrary), but this results in
Can't make a derived instance of ‘Arbitrary Foo’:
‘Arbitrary’ is not a derivable class
Try enabling DeriveAnyClass
In the data declaration for ‘Foo’
However, I can't figure out how to enble DeriveAnyClass. I just wanted to use quickcheck with my simple function! The possible values of x is Nothing, Just A and Just B. Surely this should be possible to test?
There are two reasonable approaches:
Reuse an existing instance
If there's another instance that looks similar, you can use it. The Gen type is an instance of Functor, Applicative, and even Monad, so you can easily build generators from other ones. This is probably the most important general technique for writing Arbitrary instances. Most complex instances will be built up from one or more simpler ones.
boolToFoo :: Bool -> Foo
boolToFoo False = A
boolToFoo True = B
instance Arbitrary Foo where
arbitrary = boolToFoo <$> arbitrary
In this case, Foo can't be "shrunk" to subparts in any meaningful way, so the default trivial implementation of shrink will work fine. If it were a more interesting type, you could have used some analogue of
shrink = map boolToFoo . shrink . fooToBool
Use the pieces available in Test.QuickCheck.Arbitrary and/or Test.QuickCheck.Gen
In this case, it's pretty easy to just put together the pieces:
import Test.QuickCheck.Arbitrary
data Foo = A | B
deriving (Show,Enum,Bounded)
instance Arbitrary Foo where
arbitrary = arbitraryBoundedEnum
As mentioned, the default shrink implementation would be fine in this case. In the case of a recursive type, you'd likely want to add
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics (Generic)
and then derive Generic for your type and use
instance Arbitrary ... where
...
shrink = genericShrink
As the documentation warns, genericShrink does not respect any internal validity conditions you may wish to impose, so some care may be required in some cases.
You asked about DeriveAnyClass. If you wanted that, you'd add
{-# LANGUAGE DeriveAnyClass #-}
to the top of your file. But you don't want that. You certainly don't want it here, anyway. It only works for classes that have a full complement of defaults based on Generics, typically using the DefaultSignatures extension. In this case, there is no default arbitrary :: Generic a => Gen a line in the Arbitrary class definition, and arbitrary is mandatory. So an instance of Arbitrary produced by DeriveAnyClass will produce a runtime error as soon as QuickCheck tries to call its arbitrary method.

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!

Transparently implementing a particular form of dynamic typing

The basic idea is that I have a range of functions that work on any types from a particular class, but at runtime the program is supposed to read a configuration file and extract an element of one of the types in the class.
For instance, I have a 'Coefficient' class, various instances of it, and functions of various types that are polymorphic over types of that class; at runtime one particular type of that class is to be determined, and passed around.
I'm unsure how to properly address this; I tried making up 'compound' types, doing something like:
data CompoundCoeff = CompoundInt Int | CompoundDouble Double | ...
where Int, Double, ... are instances of the class 'Coefficient'.
However, it started to become a big effort to adapt all the functions involved in the code to work with these compound types (and it's not a nice solution either, really). It would be OK if all functions had the same, easy type, e.g.
Coefficient a => a -> (stuff not involving a anymore)
but that's unfortunately not the case.
Another issue I ran into, is that I'm using type families, and have something like
class (Monoid (ColourData c), Coordinate (InputData c)) => ColourScheme c where
type ColourData c :: *
type InputData c :: *
colouriseData :: c -> (ColourData c) -> AlphaColour Double
processInput :: c -> InputData c -> ColourData c
This doesn't go through cleanly if I have to use some sort of compound ColourData datatype, like the previous one; in particular I can no longer guarantee that the data stream gives a consistent type (and not just different 'subtypes' of a compound type), and would (among other things) have to make up a bogus Monoid instance if I did make up a compound ColourData type.
I've also looked into Data.Dynamic, but again I can't see how it would properly address the issues; the exact same problems seem to appear (well, slightly worse even, given that there is only one 'generic' Dynamic type as I understand it).
Question: How can I implement dynamic datatypes subordinate to particular classes, without having to rewrite all the functions involving those data types? It would be best if I didn't have to sacrifice any type safety, but I'm not too optimistic.
The program is supposed to read a configuration file at runtime, and all the requisite functions, polymorphic over the relevant class, are to be applied.
The traditional way to provide an object that guarantees that it is an instance of typeclass Foo, but makes no additional guarantees, is like so:
{-# LANGUAGE ExistentialTypes #-}
data SomeFoo = forall a . Foo a => SomeFoo a
instance Foo SomeFoo where
-- all operations just unwrap the SomeFoo straightforwardly
or, with GADTs, which might be more readable...
data SomeFoo where
SomeFoo :: Foo a => a -> SomeFoo
One proposal would be to write a single top-level function that does all the finishing touches once you've chosen a type:
topLevel :: SomeTypeClass a => a -> IO ()
Your program can then be written something like this:
main = do
config <- readConfig
case config of
UseDouble n -> topLevel n
UseSymbolic x -> topLevel x
UseWidgetFrobnosticator wf -> topLevel wf

Resources