Given the Free Monad:
data Free f a = Var a
| Node (f (Free f a))
I tried to define an Eq instance for it:
instance (Functor f, Eq (f a)) => Eq (Free f a) where
(==) (Var x) (Var y) = x == y
(==) (Node fu1) (Node fu2) = fu1 == fu2
(==) _ _ = False
But that fails to compile:
FreeMonad.hs:17:10:
Non type-variable argument in the constraint: Eq (f a)
(Use FlexibleContexts to permit this)
In the context: (Functor f, Eq (f a))
While checking an instance declaration
In the instance declaration for ‘Eq (Free f a)’
Failed, modules loaded: none.
Specifying a constraint/pre-condition of (Functor f, Eq (f a)) seems odd to me (at least I don't think that I've seen it as a beginner before).
How can I define an Eq instance for Free f a?
There is nothing wrong with having a constraint like Eq (f a). As the error message says, you will need to enable the (harmless) FlexibleContexts GHC extension to do that, so add...
{-# LANGUAGE FlexibleContexts #-}
... to the top of your source file.
Do note, however, that (Functor f, Eq (f a)) doesn't really reflect what you are doing in your implementation of (==). Firstly, you don't need the supposition that f is a Functor here, so you can safely drop the Functor f constraint. Secondly, the constraints should match what you need to write the different cases. In the first case, you do x == y. x and y are both of type a, and so you need Eq a. For analogous reasons, the second case requires Eq (f (Free f a)) rather than Eq (f a). That means you will end up with...
(Eq (f (Free f a)), Eq a) => Eq (Free f a)
... which matches reference implementations such as the one in Control.Monad.Free.
duplode shows how to do it with flexible contexts. If you want Haskell 2010, the usual approach is to use the Eq1 class from Prelude.Extras or similar.
class Eq1 f where
(==#) :: Eq a => f a -> f a -> Bool
Then you'd use
instance (Eq1 f, Eq a) => Eq (Free f a) where ...
instance Eq1 f => Eq1 (Free f) -- default instance is fine.
I'm not at my computer right now, so I can't test this until later.
Related
Yeah, it's the unusual "why does this work" question.
I have this piece of code:
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE UndecidableInstances #-}
data F a = A (F a) | B (a (F a)) -- a :: * -> *
deriving instance (forall b. Eq b => Eq (a b)) => Eq (F a)
-- the following errors, asking me to add (Eq b) into the context
deriving instance (forall b. Eq (a b)) => Eq (F a)
The second version errors out if one define
data T a = C | D a deriving Eq
x = B C == B C
From a logical aspect, adding (Eq b) to the constraints should be something like (forall b. Eq b && Eq (a b)) => Eq (F a), because we need to keep it in the scope of forall. It is conceivable that (Eq b) is assumed implicitly, as most deriving instances do. But if so, why doesn't the second version work?
The first deriving equals the following instance
instance (forall b. Eq b => Eq (f b)) => Eq (F f) where
(==) :: F f -> F f -> Bool
A a1 == A b1 = (==) #(F f) a1 b1
B a1 == B b1 = (==) #(f (F f)) a1 b1
_ == _ = False
Given that equality is closed under f (forall b. Eq b => Eq (f b)) the following constraints are wanted from (==) #(F f) and (==) #(f (F f))
Eq (F f)
Eq (f (F f))
For the first one is the equality instance we are writing/deriving: Eq (F f) which holds in the current context (Eq is closed under f). So that constraint is satisfied.
The second one asks for equality for our lifted type: Eq (f (F f)) which follows from the context: Eq being closed under f.
If we instantiate b with F f we see that our lifted type supports equality Eq (F f) => Eq (f (F f)) if the type we are defining supports equlity.. which it does (1.).
The second instance compiles on GHC Head.
deriving instance (forall b. Eq (f b)) => Eq (F f)
If you know that Eq (f b) holds for any b, you can solve 1. and 2. by instantiating b with F f.
After playing around for a little bit, I think I nailed down the problem. Sorry for editing the question frequently! I oversimplified the code, and didn't test carefully.
The data T a = C | D a derives an Eq instance that requires Eq a. Without that, the forall b. Eq (T b) premise cannot be satisfied. With forall b. (Eq b) => Eq (T b), we can use Eq b to obtain the required equality predicate on a.
I have an associated type family Bar in a type class Foo. Foo' requires that Bar f ~ Bar (f a) for all a, but in another function test I get an error Couldn't match type 'Bar f' with 'Bar (f a)', even though it depends on Foo' f. The code:
{-# LANGUAGE TypeFamilies, PolyKinds, QuantifiedConstraints #-}
import Data.Proxy
class Foo f where
type Bar f
class (Foo f, forall a. Foo (f a), forall a. Bar f ~ Bar (f a)) => Foo' f where
test :: Foo' f => Proxy (f a) -> Bar (f a) -> Bar f
test _ = id
Why can't GHC figure out this type equality and is there a way to help the typechecker without asserting the concrete equality in test?
Type families and quantified constraints don't mix. Much even less with type equalities. But there is a way to keep them separate to achieve more or less the same result.
A quantified constraint is actually restricted in the ways it can be used. It's not sufficient to know that a constraint holds for all types, you also need a way to know which types you need to specialize it to. GHC achieves this by representing quantified constraints as a sort of "local instance" subject to the common rules of instance resolution. I'm not sure quantified type equalities even mean anything. In summary, it's not enough that a quantified constraint can be instantiated to do what we want; that instantiation must happen in the regular course of instance resolution, and that puts restrictions on the allowed forms of quantified constraints.
The trick is to define a class synonym for the body of the quantified constraint:
class (Bar f ~ Bar (f a)) => EBar f a
instance (Bar f ~ Bar (f a)) => EBar f a
That way we can rewrite the quantified constraint as forall x. EBar f x, no type families in sight:
class (Foo f, forall a. Foo (f a), forall x. EBar f x) => Foo' f where
To use this class, we need an explicit function to specialize the quantified constraint (the problem is that if we use an equality Bar f ~ Bar (f a) directly, the type checker can't relate that to the quantified constraint forall x. EBar f x, which looks nothing like it):
-- Morally a function on constraints `(forall x. EBar f x) => EBar f a`
-- in continuation-passing style: (x => y) is isomorphic to forall r. (y => r) -> (x => r)
ebar :: forall f a r. (EBar f a => Proxy (f a) -> r) -> (forall x. EBar f x) => Proxy (f a) -> r
ebar f = f
test :: Foo' f => Proxy (f a) -> Bar (f a) -> Bar f
test = ebar (\_ -> id)
{-# LANGUAGE RankNTypes, MultiParamTypeClasses, FlexibleInstances, TypeFamilies, PolyKinds, QuantifiedConstraints #-}
import Data.Proxy
class Foo f where
type Bar f
class (Foo f, forall a. Foo (f a), forall a. EBar f a) => Foo' f where
class (Bar f ~ Bar (f a)) => EBar f a
instance (Bar f ~ Bar (f a)) => EBar f a
ebar :: forall f a r. (EBar f a => Proxy (f a) -> r) -> (forall x. EBar f x) => Proxy (f a) -> r
ebar f = f
test :: Foo' f => Proxy (f a) -> Bar (f a) -> Bar f
test = ebar (\_ -> id)
I am trying to use this blogpost's approach to higher-kinded data without dangling Identity functors for the trival case together with quantified-constraint deriving:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE QuantifiedConstraints, StandaloneDeriving, UndecidableInstances #-}
module HKD2 where
import Control.Monad.Identity
type family HKD f a where
HKD Identity a = a
HKD f a = f a
data Result f = MkResult
{ foo :: HKD f Int
, bar :: HKD f Bool
}
deriving instance (forall a. Show a => Show (HKD f a)) => Show (Result f)
This results in the infuriatingly self-contradicting error message:
Could not deduce Show (HKD f a)
from the context: forall a. Show a => Show (HKD f a)
Is there a way to do this without being long-winded about it and doing
deriving instance (Show (HKD f Int), Show (HKD f Bool)) => Show (Result f)
?
tl;dr, gist: https://gist.github.com/Lysxia/7f955fe5f2024529ba691785a0fe4439
Boilerplate constraints
First, if the question is about avoiding repetitive code, this is mostly addressed by generics alone, without QuantifiedConstraints. The constraint (Show (HKD f Int), Show (HKD f Bool)) can be computed from the generic representation Rep (Result f). The generic-data package (disclaimer: that I wrote) implements this:
data Result f = MkResult (HKD f Int) (HKD f Bool)
deriving Generic
-- GShow0 and gshowsPrec from Generic.Data
instance GShow0 (Rep (Result f)) => Show (Result f) where
showsPrec = gshowsPrec
or with DerivingVia:
-- Generically and GShow0 from Generic.Data
deriving via Generically (Result f) instance GShow0 (Rep (Result f)) => Show (Result f)
Quantified constraints with type families
Nevertheless, the constraint (Show (HKD f Int), Show (HKD f Bool)) may be less than ideal for various reasons. The QuantifiedConstraints extension may seem to provide a more natural constraint forall x. Show (HKD f x):
it would entail the tuple (Show (HKD f Int), Show (HKD f Bool));
contrary to that tuple, it does not blow up in size when the record gets big, and does not leak the field types of Result as they may be subject to change.
Unfortunately, that constraint is actually not well-formed. The following GHC issue discusses the problem in detail: https://gitlab.haskell.org/ghc/ghc/issues/14840 I don't understand all of the reasons yet, but in brief:
Quantified constraints won't work directly with type families for the foreseeable future, for reasons both theoretical and practical;
But there is a workaround for most use cases.
A quantified constraint should be viewed as a sort of "local instance". The general rule then is that type families are not allowed in the head of any instance ("instance head" = the HEAD in the following instance ... => HEAD where). So forall a. Show (HKD f a) (viewed as a "local" instance Show (HKD f a)) is illegal.
Quantified constraint smuggler
The following solution is credited to Icelandjack (Source: this comment from the ticket linked earlier; thanks also to Ryan Scott for relaying it.)
We can define another class that's equivalent to Show (HKD f a):
class Show (HKD f a) => ShowHKD f a
instance Show (HKD f a) => ShowHKD f a
Now forall x. ShowHKD f x is a legal constraint that morally expresses the intended forall x. Show (HKD f x). But it's not at all obvious how to use it. For example, the following snippet fails to type check (note: we can easily ignore the ambiguity issues):
showHKD :: forall f. (forall x. ShowHKD f x) => HKD f Int -> String
showHKD = show
-- Error:
-- Could not deduce (Show (HKD f Int)) from the context (forall x. ShowHKD f x)
This is counterintuitive, because ShowHKD f x is equivalent to Show (HKD f x) which can of course be instantiated with Show (HKD f Int). So why is that rejected? The constraint solver reasons backwards: the use of show first requires a constraint Show (HKD f Int), but the solver is immediately stuck. It sees forall x. ShowHKD f x in the context, but there is no clue for the solver to know that it should instantiate x to Int. You should imagine that at this point, the constraint solver has no idea of any relationship between Show and ShowHKD. It just wants a Show constraint, and there is none in the context.
We can help the constraint solver as follows, by annotating the body of the function with the needed instantiation(s) of ShowHKD f x, here ShowHKD f Int:
showHKD :: forall f. (forall x. ShowHKD f x) => HKD f Int -> String
showHKD = show :: ShowHKD f Int => HKD f Int -> String
This annotation provides the constraint ShowHKD f Int to the body show, which in turn makes the superclass available Show (HKD f Int) so show can be immediately satisfied. On the other side, the annotation requires the constraint ShowHKD f Int from its context, which provides forall x. ShowHKD f x. Those constraints match, and that leads the constraint solver to instantiate x appropriately.
Deriving Show with quantified constraints
With this, we can implement Show with a quantified constraint, using generics to fill out the body, and with some annotations to instantiate the quantified constraint,
(ShowHKD f Int, ShowHKD f Bool):
instance (forall a. Show a => ShowHKD f a) => Show (Result f) where
showsPrec = gshowsPrec :: (ShowHKD f Int, ShowHKD f Bool) => Int -> Result f -> ShowS
As before, those constraints can be automated with generics, so the only thing that changes in this implementation from one type to another is the name Result:
instance (forall a. Show a => ShowHKD f a) => Show (Result f) where
showsPrec = gshowsPrec :: ShowHKDFields f (Rep (Result HKDTag)) => Int -> Result f -> ShowS
-- New definitions: ShowHKDFields and HKDTag; see gist at the end.
And with a bit more effort, we can have DerivingVia too:
deriving via GenericallyHKD Result f instance (forall a. Show a => ShowHKD f a) => Show (Result f)
-- New definition: GenericallyHKD; see gist.
Full gist: https://gist.github.com/Lysxia/7f955fe5f2024529ba691785a0fe4439
I don't think you can do such thing, but I could certainly be wrong. In your example you are missing an extra constraint Show (f a) in order for it to be complete:
deriving instance (forall a. (Show a, Show (f a)) =>
Show (HKD f a)) => Show (Result f)
But that would mean that Show instance for f a cannot depend on a, which can be true for specific f, but not in general.
Edit
But at the same time it is possible to write something like that without the TypeFamilies:
data Bar f = MkBar (f Int)
deriving instance (forall a . Show a => Show (f a)) => Show (Bar f)
So, I am not sure why GHC can't figure it out.
Edit 2
Here is an interesting observation, this compiles:
type family HKD f a where
-- HKD Identity a = a
HKD f Int = Int
HKD f a = f a
data Result f = MkResult
{ foo :: HKD f Int
, bar :: HKD f Bool
}
deriving instance (forall a. Show a => Show (f a)) => Show (Result f)
and works as expected:
λ> show $ MkResult 5 (Just True)
"MkResult {foo = 5, bar = Just True}"
So, it looks like matching on f somehow messes up the type checker.
Worth noting, that restricting to Show (HDK f a) even for the simplified example also gives the same compile time error as in the question:
deriving instance (forall a. Show a => Show (HKD f a)) => Show (Result f)
Aeson provides FromJSON1 and ToJSON1 type classes. These are similar to the Eq1 and Show1 classes defined in the Data.Functor.Classes module.
My understanding of the Eq1 and Show1 classes is that they are needed to be able to express constraints on arguments of transformers without using extensions like FlexibleContexts and UndecidableInstances.
The example from the documentation in the Data.Functor.Classes module is as follows:
Assume we have a data type that acts as a transformer: T. For an example, let's have it be isomorphic to IdentityT:
data T f a = T (f a)
The kind of T is as follows:
T :: (* -> *) -> * -> *
If there is an Eq1 instance for f, it is possible to use it when writing the Eq1 instance for T f:
instance Eq1 f => Eq1 (T f) where
liftEq :: (a -> b -> Bool) -> T f a -> T f b -> Bool
liftEq eq (T fa1) (T fa2) = liftEq eq fa1 fa2
If we have an Eq1 instance for f, an Eq instance for a, and the Eq1 instance for T f above is in scope, we can easily write the Eq instance for T f a:
instance (Eq1 f, Eq a) => Eq (T f a) where
(==) :: T f a -> T f a -> Bool
(==) = eq1
The type of eq1 is defined as follows:
eq1 :: (Eq1 h, Eq a) => h a -> h a -> Bool
In our instance above, h becomes T f, so the type of eq1 can be thought of as the following:
eq1 :: Eq a => T f a -> T f a -> Bool
Now, the Eq1, Show1, etc classes make sense. It seems like it makes it easier to write instances of Eq, Show, etc for transformers.
However, I'm wondering what types FromJSON1 and ToJSON1 are used for in Aeson? I rarely have transformers that I want to turn to and from JSON.
Most of the data types I end up changing to JSON are normal types (not type constructors). That is to say, types with the kind *. I also uses types like Maybe with a kind of * -> *.
However, I don't think I often create ToJSON or FromJSON instances for transformers, like the T above. What is a transformer that is often used to go to and from JSON? Am I missing out on some helpful transformers?
Eq1 offers another feature that you haven't discussed in your exposition: it lets you write a function that calls (==) at many different types, without necessarily knowing ahead of time which types you will use it on.
I'll give a toy example; hopefully you can see through the apparent uselessness of this example to the reason Eq1 gives you some interesting powers.
Imagine you want to make a tree that is parameterized on the branching factor, so you parameterize it by the child container. So values might look like this:
{-# LANGUAGE GADTs #-}
data Tree m a where
Branch :: Tree m (m a) -> Tree m a
Leaf :: a -> Tree m a
For example, I can get binary trees with Tree Pair, trinary trees with Tree Triple, finger trees with Tree TwoThree, and rose trees with Tree [], where data Pair a = Pair a a, data Triple a = Triple a a a, and data TwoThree a = Two a a | Three a a a. Now I would like to write an Eq instance for this. If we only rely on Eq constraints, we can't get where we want to go. Let's try:
instance Eq (Tree m a) where
Leaf a == Leaf a' = a == a'
Branch t == Branch t' = t == t'
_ == _ = False
Naturally, GHC complains that it doesn't know how to compare a and a' for equality. So add Eq a to the context:
instance Eq a => Eq (Tree m a) where ...
Now GHC complains that it doesn't know how to compare m as for equality in the Branch case. Makes sense.
instance (Eq a, Eq (m a)) => Eq (Tree m a) where ...
Still no go! Now the implementation of (==) :: Tree m a -> Tree m a -> Bool has a recursive call to (==) :: Tree m (m a) -> Tree m (m a) -> Bool in its Branch case, hence must provide the context (Eq (m a), Eq (m (m a))) to make that recursive call. Okay, let's add that to the instance context...
instance (Eq a, Eq (m a), Eq (m (m a))) => Eq (Tree m a) where ...
Still no good. Now the recursive call has to prove even more stuff! What we'd really like to say is that if we have Eq b, then we have Eq (m b), for all bs and not just for the specific a being used as Tree's second parameter.
instance (Eq a, (forall b. Eq b => Eq (m b))) => Eq (Tree m a) where ...
Of course that's totally not a thing in Haskell. But Eq1 gives us that:
instance Eq1 m => Eq1 (Tree m) where
liftEq (==) (Leaf a) (Leaf a') = a == a'
liftEq (==) (Branch t) (Branch t') = liftEq (liftEq (==)) t t'
liftEq (==) _ _ = False
instance (Eq1 m, Eq a) => Eq (Tree m a) where
(==) = eq1
Here the Eq1 m constraint is serving the role we asked for before, namely, that all of (Eq a, Eq (m a), Eq (m (m a)), ...) are possible.
The ToJSON1 and FromJSON1 classes serve a similar role: they give you a single constraint that you can give that amounts to a potentially infinite collection of ToJSON and FromJSON constraints, so that you can choose which ToJSON or FromJSON constraint you need in a data-driven way and be guaranteed that it's available.
I'm developing a class representing key/value mappings, and I've got a function which is basically like alterF:
class C t where
...
alterF :: Functor f =>
(Maybe (Value t) -> f (Maybe (Value t))) -> Key t -> t -> f t
Unfortunately, this breaks GeneralisedNewtypeDeriving. In some cases, this is reasonable, as GeneralisedNewtypeDeriving from what I understand essentially uses Coercible and the function coerce. Coercible represents types which are representationally equal, i.e. they have the same representation at run time, so we can convert between them for free. For example, given:
newtype T a = T a
we have:
Coercible a (T a)
Coercible (T a) a
but we don't have (in general):
Coercible (f a) (f (T a))
Coercible (f (T a)) (f a)
For example, GADTs violate this representational equality. But there are lots of values of f that do work. For example:
Coercible (Maybe a) (Maybe (T a))
Coercible (Maybe (T a)) (Maybe a)
Coercible [a] [T a]
Coercible [T a] [a]
Coercible (Identity a) (Identity (T a))
Coercible (Identity (T a)) (Identity a)
It also occurs to me that this instance could be written:
Functor f => Coercible (f a) (f (T a))
Functor f => Coercible (f (T a)) (f a)
Just using fmap. Unlike the usual coerce, this wouldn't be free at runtime, but it will work.
So I've got a class with 10 functions, 9 of which work fine with GeneralisedNewtypeDeriving. There's just this final one which doesn't, which could be resolved mechanically using fmap. Do I have to write custom wrapping/unwrapping implementations for all my class functions, or is there a way to either require me to write the implementation for just the problem function or alternatively coax GHC into using fmap as part of it's GeneralisedNewtypeDeriving?
If f is a Functor, you can make a "representational wrapper" for it
data Rep f a where
Rep :: (b -> a) -> f b -> Rep f a
which is isomorphic to f except that it is representational in a, by what is essentially existential quantification over any nominal variance f might have. I think this construction happens to have some fancy category theory name but I don't remember what it is. To get the f a back out of a Rep f a, you need to use f's Functorhood.
You can use this wrapper in your method, ensuring that your class varies representationally.
alterFRep :: (Functor f)
=> (Maybe (Value t) -> Rep f (Maybe (Value t))) -> Key t -> t -> Rep f t
And then make the real "method" just a regular function in terms of it by using the isomorphism with Rep f. You can also make a convenience method for instance authors:
toAlterFRep ::
(forall f t. (Functor f) => (Maybe (Value t) -> f (Maybe (Value t))) -> Key t -> t -> f t)
-> (forall f t. (Functor f) => (Maybe (Value t) -> Rep f (Maybe (Value t))) -> Key t -> t -> Rep f t)
so they don't have to worry about what the heck Rep is, they just implement alterF normally and use toAlterFRep on it.