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
?