phaazon
phaazon

Reputation: 2002

Make a class an instance of another class

I have a class called Foo that owns a function gen :: Int -> [Foo]. For instance, I could make an instance of Foo that way:

data FooTest = FooTest Int

instance Foo FooTest where
  gen n = replicate n (FooTest 0)

Now, let’s imagine I have another class called Bar that defines a function bar :: Bar -> IO (). Each instance of Foo has to be an instance of Bar, but the Bar implementation is quite the same for each instance. Here’s an example:

class Foo f where
  gen :: Int -> [f]

class Bar b where
  bar :: b -> IO ()

instance Bar Foo where -- obviously that doesn’t work
  bar _ = putStrLn "bar through any Foo instance"

instance (Foo f) => Bar f where -- this needs the FlexibleInstance GHC extension first, then it still throws shit saying that the constraint is not smaller that I don’t shit
  bar _ = putStrLn "bar through any Foo instance"

The problem here is I can’t find any ways to make a class an instance of another to mention the fact that any instance of the first class will share the same implementation for instancing the other class.

Any idea?

Thanks in advance.

Upvotes: 8

Views: 866

Answers (1)

Tikhon Jelvis
Tikhon Jelvis

Reputation: 68172

You can accomplish exactly what you want using your last instance with two extensions: FlexibleInstances and UndecidableInstances.

Just like the name implies, the second extension allows you to potentially write instances that do not terminate. This could lead to an infinite loop at compile time; however, the implementation is arbitrarily capped at a certain recursion depth, so you should not have actually infinite compile times.

I do not know of any way to do this without any extensions at all. However, using extensions is not inherently bad unless you might want to use other compilers in the future.

Also, a random style note: the parentheses are optional if you only have one constraint. So you could write it as:

instance Foo f => Bar f where ...

This isn't very important, but I think the second version looks better.

Upvotes: 4

Related Questions