Question about typeclass & constraints

Hello Consider the following data, class and instance: class PP m where create :: a -> m a data A a = A a instance PP A where create a = A a And then: class CB a where fb :: a -> Int data B m a = B (m a) If I try to define an instance of PP for B with the following implementation: instance (PP m) => PP (B m) where create a = let _ = fb a in B (create a) GHC issues the (expected) error: Could not deduce (CB a) arising from a use of 'fb' from the context (PP m). So the workaround I am using is to define a new class PP' where the type a is made more explicit. That allows the constraint (CB a) to be stated in an instance declaration. class PP' m a where create' :: a -> m a instance (PP m) => PP' m a where create' = create instance (PP m, CB a) => PP' (B m) a where create' a = let _ = fb a in B (create a) So, my question is: is there a way to achieve the same results without having to create the new class PP'? Thank you for your help J-C

On Tue, Apr 08, 2014 at 09:25:17AM +0200, jean-christophe mincke wrote:
instance (PP m) => PP (B m) where create a = let _ = fb a in B (create a)
Your use of 'fb' here is baffling. Am I right in thinking you have tried to simplify your problem for clarity? If so I think you have simplified too far! Could you give an example where the use of 'fb' actually matters? Tom

Tom, Yes of course it is simplified for clarity. Here is a modified version where fb does something (a bit more usefull) class PP m where create :: a -> m a data A a = A a instance PP A where create a = A a class CB a where fb :: a -> a data B m a = B (m a) instance (PP m) => PP (B m) where create a = let a' = fb a in B (create a') class PP' m a where create' :: a -> m a instance (PP m) => PP' m a where create' = create instance (PP m, CB a) => PP' (B m) a where create' a = let a' = fb a in B (create a') Actually I ran into that problem when trying to add a kind of rule engine layer above the Persistent typeclass. Given the complexity of these typeclass, I think it is more practical to reason about a simpler form of the same problem. Thanks J-C On Tue, Apr 8, 2014 at 9:42 AM, Tom Ellis < tom-lists-haskell-cafe-2013@jaguarpaw.co.uk> wrote:
On Tue, Apr 08, 2014 at 09:25:17AM +0200, jean-christophe mincke wrote:
instance (PP m) => PP (B m) where create a = let _ = fb a in B (create a)
Your use of 'fb' here is baffling. Am I right in thinking you have tried to simplify your problem for clarity? If so I think you have simplified too far!
Could you give an example where the use of 'fb' actually matters?
Tom _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Tue, Apr 08, 2014 at 10:17:50AM +0200, jean-christophe mincke wrote:
class PP m where create :: a -> m a
data A a = A a instance PP A where create a = A a
class CB a where fb :: a -> a
data B m a = B (m a) instance (PP m) => PP (B m) where create a = let a' = fb a in B (create a')
Thanks for the clarified example. The failure here is not a technicality. There's a very good reason it can't work this way: 'create' is required to be parametrically polymorphic in 'a' but 'fb' is specialised to the *particular* 'a' in the typeclass constraint. Thus you can't use 'fb' to implement 'create'!
class PP' m a where create' :: a -> m a
instance (PP m) => PP' m a where create' = create
instance (PP m, CB a) => PP' (B m) a where create' a = let a' = fb a in B (create a')
create' is not required to be parametric, hence you can use 'fb' in its implementation. Without knowing more about your specific use case it's hard to know what to suggest. Personally speaking though, I am not a fan of complicated typeclass algebra, and prefer to create and pass dictionaries explicitly for all but the most trivial cases. Tom

I've run into problems like this as well. Often you can redesign a bit
to fix things, although it depends on the application how to do that.
Two other technical options in addition to your PP':
You can add a constraint to the 'create' function. It depends on the
actual semantics if this makes sense, I guess:
class PP2 m where
create :: CB a => a -> m a
You can use ConstraintKinds [1] to add a constraint to create
depending on the type 'm':
type family C m a :: Constraint
class PP3 m where
create :: C m a => a -> m a
This way you can choose if you want to add a constraint and which one,
depending on the 'm'.
If you can solve it without any of these things, I'd probably prefer
that personally, though. As Tom also said, complicated type class
constructions often make your program more difficult to understand and
maintain.
Erik
[1] http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/constraint-kind.html
On Tue, Apr 8, 2014 at 10:17 AM, jean-christophe mincke
Tom,
Yes of course it is simplified for clarity.
Here is a modified version where fb does something (a bit more usefull)
class PP m where create :: a -> m a
data A a = A a instance PP A where create a = A a
class CB a where fb :: a -> a
data B m a = B (m a) instance (PP m) => PP (B m) where create a = let a' = fb a in B (create a')
class PP' m a where create' :: a -> m a
instance (PP m) => PP' m a where create' = create
instance (PP m, CB a) => PP' (B m) a where create' a = let a' = fb a in B (create a')
Actually I ran into that problem when trying to add a kind of rule engine layer above the Persistent typeclass. Given the complexity of these typeclass, I think it is more practical to reason about a simpler form of the same problem.
Thanks
J-C
On Tue, Apr 8, 2014 at 9:42 AM, Tom Ellis
wrote: On Tue, Apr 08, 2014 at 09:25:17AM +0200, jean-christophe mincke wrote:
instance (PP m) => PP (B m) where create a = let _ = fb a in B (create a)
Your use of 'fb' here is baffling. Am I right in thinking you have tried to simplify your problem for clarity? If so I think you have simplified too far!
Could you give an example where the use of 'fb' actually matters?
Tom _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Thank you
The problem here is that I cannot modify the original PP class (In fact it,
in the real life, it is PersistStore).
So I guess I am left with PP' solution.
Regards
J-C
On Tue, Apr 8, 2014 at 10:53 AM, Erik Hesselink
I've run into problems like this as well. Often you can redesign a bit to fix things, although it depends on the application how to do that. Two other technical options in addition to your PP':
You can add a constraint to the 'create' function. It depends on the actual semantics if this makes sense, I guess:
class PP2 m where create :: CB a => a -> m a
You can use ConstraintKinds [1] to add a constraint to create depending on the type 'm':
type family C m a :: Constraint
class PP3 m where create :: C m a => a -> m a
This way you can choose if you want to add a constraint and which one, depending on the 'm'.
If you can solve it without any of these things, I'd probably prefer that personally, though. As Tom also said, complicated type class constructions often make your program more difficult to understand and maintain.
Erik
[1] http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/constraint-kind.html
Tom,
Yes of course it is simplified for clarity.
Here is a modified version where fb does something (a bit more usefull)
class PP m where create :: a -> m a
data A a = A a instance PP A where create a = A a
class CB a where fb :: a -> a
data B m a = B (m a) instance (PP m) => PP (B m) where create a = let a' = fb a in B (create a')
class PP' m a where create' :: a -> m a
instance (PP m) => PP' m a where create' = create
instance (PP m, CB a) => PP' (B m) a where create' a = let a' = fb a in B (create a')
Actually I ran into that problem when trying to add a kind of rule engine layer above the Persistent typeclass. Given the complexity of these typeclass, I think it is more practical to reason about a simpler form of the same problem.
Thanks
J-C
On Tue, Apr 8, 2014 at 9:42 AM, Tom Ellis
wrote: On Tue, Apr 08, 2014 at 09:25:17AM +0200, jean-christophe mincke wrote:
instance (PP m) => PP (B m) where create a = let _ = fb a in B (create a)
Your use of 'fb' here is baffling. Am I right in thinking you have
On Tue, Apr 8, 2014 at 10:17 AM, jean-christophe mincke
wrote: tried to simplify your problem for clarity? If so I think you have simplified too far!
Could you give an example where the use of 'fb' actually matters?
Tom _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (3)
-
Erik Hesselink
-
jean-christophe mincke
-
Tom Ellis