I have a code to the following scheme:
class First s where
func1 :: s -> s
class Second a where
func2 :: s -> a s
data D s = D {value :: s}
myFunc2 :: First s => s -> D s
myFunc2 = undefined
In common func2's argument could not be instance of First. I want to make D instance of Second in only that cases when it's value instance of First. Then I want to get this instance:
instance Second D where
func2 = myFunc2
But I get an error:
No instance for (First s)
arising from a use of `myFunc2'
Okay, let instance be:
instance First s => Second D where
func2 = myFunc2
But this gives error:
Ambiguous constraint `First s'
At least one of the forall'd type variables mentioned by the constraint
must be reachable from the type after the '=>'
In the instance declaration for `Second D'
So, is there a way to get instance of class with some conditions from other classes, but without all type variables after '=>'?
I think it helps to think about what is meant qualitatively by
class Second a where
func2 :: s -> a s
A Second
instance promises that func2
is defined for any type s
. But that's not true of myFunc2
, because myFunc2
is only defined for those s
for which there exists a First
instance. This means that as you have defined First
and Second
, it is not possible to use myFunc2
in a Second
instance (unless there existed a catch-all forall s . First s
instance, but I'm assuming not, or you wouldn't have bothered to make a typeclass).
So, you will have to change at least one thing. You could redefine Second
as Grzegorz suggested. If you don't like that, you could redefine Second
like
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
class Second a s where
func2 :: s -> a s
instance First s => Second D s where
func2 = myFunc2
Note that this is saying something different than what you wrote originally, because now a Second
instance does not guarantee that func2
is polymorphic. But I think this is closer to what you mean when you say "make D instance of Second in only that cases when it's value instance of First". Maybe it will be acceptable in your code.
The exact solution will depend on what the code is trying to do, but the problem is that the type signature you give to func2
does not mention the First s
constraint, whereas your definition of func2
for the Second D
instance needs it. The following compiles:
class First s where
func1 :: s -> s
class Second a where
func2 :: First s => s -> a s
data D s = D {value :: s}
myFunc2 :: First s => s -> D s
myFunc2 = undefined
instance Second D where
func2 = myFunc2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With