I have this datatype:
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
import Data.Proxy
import Data.Constraint
import Data.Kind
type Foo :: (Type -> Constraint) -> Type
data Foo c = Foo (Proxy c) (forall x. c x => x -> x)
It doesn't look very useful, but it's a reduced version of a datatype that is useful.
I want to use the constraints package to write a mapping function over the constraint, using evidence of entailment:
restrictFoo :: forall less more. (forall v. more v :- less v) -> Foo less -> Foo more
The idea is that if the more constraint is stronger than the less constraint, it should be possible to convert a less constrained function inside Foo into a more constrained one.
I think the forall v is in the correct place. If it ranged across all of the signature, the caller would be the one who chose v, which seems counterproductive when working with the polymorphic functions.
This naive attempt at implementation doesn't work:
restrictFoo :: forall less more. (forall v. more v :- less v) -> Foo less -> Foo more
restrictFoo (Sub Dict) (Foo proxy f) =
Foo (Proxy @more) f
It fails with
* Could not deduce: more v0 arising from a pattern
* In the pattern: Dict
In the pattern: Sub Dict
...
* Could not deduce: less x arising from a use of `f'
from the context: less v0
How to write correctly the body of restrictFoo?