The use of Forall in Haskell - haskell

Data.Constraint.Forall provides some quantification over constraints, however I fail to see how it can be used. Consider the following:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Forall where
import Prelude
import Data.Constraint.Forall
class Monoid (f a) => MonoidalFunctor f a
testfun :: Forall (MonoidalFunctor f) => (a -> f a) -> [a] -> f a
testfun = foldMap
testfun' :: Monoid (f a) => (a -> f a) -> [a] -> f a
testfun' = foldMap
I thought testfun would typecheck because Forall (MetaMonoid f) would work like forall a. Metamonoid f a, implying forall a. Monoid (f a) because of superclass constraint, but it doesn't.
Why does it not work and is there any workaround? I want to avoid having to write a lot of constraints like MyClass (f MyData) for different MyData types in my function where I know that any useful f will have instances for any f MyData anyway.

Use inst
inst :: forall p a. Forall p a :- p a
inst witness that, if you have forall a. p a, then you can set a to whatever you please and get p a out.
An entailment (:-) is
newtype a :- b = Sub (a => Dict b)
data Dict a = a => Dict
so, by pattern-matching on it, you can reveal the instance within it:
testfun :: forall f a. Forall (MonoidalFunctor f) => (a -> f a) -> [a] -> f a
testfun = case inst #(MonoidalFunctor f) #a of Sub Dict -> foldMap
(type applications/signatures necessary) or you can use (\\):
(\\) :: a => (b => r) -> a :- b -> r
testfun = foldMap \\ inst #(MonoidalFunctor f) #a
which reads "given that a is true and a value of r that also needs b to be true, followed by a value that can prove that b is true given a, make an r. If you rearrange a bit
(\\) :: (b => c) -> (a :- b) -> (a => c)
it looks quite a bit like function composition.
The reason for this dance is simply because it's beyond the reach of GHC to infer that Forall c means it can derive c a for any a; after all, that's why constraints exists. So, you have to be a bit more explicit about it.

Related

instance constraints compare type-family constraints

Usually I reckon type-families are similarly expressive as compared with typeclasses/instances -- the difference is awkwardness/ergonomics of the code. In this case I have code working with type-families to raise a constraint, but the equivalent typeclass code won't compile. (* Could not deduce (Eq a) ... when (Eq a) is exactly the constraint I'm supplying.) Is this a case typeclasses just can't express, or am I doing something wrong?
data Set a = NilSet | ConsSet a (Set a) deriving (Eq, Show, Read)
-- fmap over a Set, squishing out duplicates
fmapSet :: (Eq a, Eq b ) => (a -> b) -> Set a -> Set b
fmapSet f NilSet = NilSet
fmapSet f (ConsSet x xs) = uqCons (f x) (fmapSet f xs)
uqCons fx fxs | sElem fx fxs = fxs
| otherwise = ConsSet fx fxs
sElem fx NilSet = False
sElem fx (ConsSet fy fys) = fx == fy || sElem fx fys
I want to call that fmap via a Functor-like class, with a constraint that the data-structure is well-formed. Either of these approaches with type-families work (based on this answer, but preferring a standalone family).
{-# LANGUAGE ConstraintKinds, TypeFamilies #-}
import Data.Kind (Type, Constraint)
type family WFTF (f :: * -> *) a :: Constraint
type instance WFTF Set a = Eq a
class WFTFFunctor f where
wftFfmap :: (WFTF f a, WFTF f b) => (a -> b) -> f a -> f b
instance WFTFFunctor Set where
wftFfmap = fmapSet
type family WFTF2 c_a :: Constraint
type instance WFTF2 (Set a) = Eq a
class WFTF2Functor f where
wftF2fmap :: (WFTF2 (f a), WFTF2 (f b)) => (a -> b) -> f a -> f b
instance WFTF2Functor Set where
wftF2fmap = fmapSet
The equivalent (I think) typeclass at least compiles providing I don't give an implementation for the method:
class WFT c_a where
instance Eq a => WFT (Set a)
class WFTFunctor f where
wftfmap :: (WFT (f a), WFT (f b)) => (a -> b) -> f a -> f b
instance WFTFunctor Set where wftfmap f xss = undefined -- s/b fmapSet f xss
Inferred :t (\ f (xss :: Set a) -> wftfmap f xss) :: (Eq a, Eq b) => (a -> b) -> Set a -> Set b -- which is exactly the type of fmapSet. But if I put that call to fmapSet f xss in place of undefined, rejected:
* Could not deduce (Eq a) arising from a use of `fmapSet'
from the context: (WFT (Set a), WFT (Set b))
bound by the type signature for:
wftfmap :: forall a b.
(WFT (Set a), WFT (Set b)) =>
(a -> b) -> Set a -> Set b
at ...
Possible fix:
add (Eq a) to the context of
the type signature for:
wftfmap :: forall a b.
(WFT (Set a), WFT (Set b)) =>
(a -> b) -> Set a -> Set b
WFT (Set a) implies raises Wanted (Eq a), so I shouldn't need to add it. (And if I do via InstanceSignatures, rejected because it's not as general as the inferred constraint.) [In response to #dfeuer's answer/my comment] True that there's nothing in the instance decl to Satisfy (Eq a), but fmapSet's sig also Wants (Eq a) so (why) doesn't that ensure the constraint gets satisfied at the call site?
I've tried decorating everything with ScopedTypeVariables/PatternSignatures to make the constraints more explicit. I've tried switching on ImpredicativeTypes (GHC 8.10.2). I sometimes get different rejection messages, but nothing that compiles.
If I take away the WFT (Set a) and (Eq a) from fmapSet's signature, I get a similar rejection * Could not deduce (Eq b) .... Yes I know that rejection message is a FAQ. In the q's I've looked through, the constraint is indeed unsatisfiable. But then in this case
a) why does the version with implementation undefined typecheck;
b) isn't the constraint wanted from WFT (Set a) getting satisfied
by fmapSet having the (Eq a)?)
Addit: To explain a bit more about what I'm expecting in terms of Wanted/Satisfied constraints:
There's no signature given for uqCons, nor for sElem, which it calls. In sElem there's a call to (==), that raises Wanted (Eq b) in sElem's sig, which gets passed as a Wanted in the sig for uqCons, which gets passed as a Wanted in the sig for fmapSet, which does have a sig given including (Eq b).
Similarly the Set instance for method wftfmap raises Wanted (Eq a, Eq b); I expect it can use that to Satisfy the Wanted arising from the call to fmapSet.
There's a huge difference between superclass constraints and instance constraints. A superclass constraint is something required to form any instance of the class, and is available whenever the subclass constraint is in force. An instance constraint is required to form a specific instance, and is not automatically available when the class constraint is in force. This difference is pretty deeply wired into the system, and is reflected in the Core representations. In Core:
A class is a type of records of class methods and superclasses.
An instance is a value of a class type or a function from its instance constraints to such a value.
Once a "dictionary function" is called to produce an instance dictionary, you only have the dictionary, not the arguments that were used to create it.
[re #Ben's comment to #dfeuer's answer] not something you have on the inside to implement wftfmap.
OK I can have the right sig on the inside:
-- class/instance WFT, funcs fmapSet, uqCons, sElem as before
{-# LANGUAGE InstanceSigs, QuantifiedConstraints #-}
class WFTQFunctor f where
wftQfmap :: (WFT (f a), WFT (f b)) => (a -> b) -> f a -> f b
instance (forall b. (WFT (Set b) => Eq b)) => WFTQFunctor Set where
wftQfmap :: (Eq a, Eq b) => (a -> b) -> (Set a) -> (Set b) -- yay
wftQfmap f xss = fmapSet f xss
Compiles with a warning that I can suppress with -XMonoLocalBinds:
* The constraint `WFT (Set b)' matches
instance Eq a => WFT (Set a)
This makes type inference for inner bindings fragile;
either use MonoLocalBinds, or simplify it using the instance
* In the instance declaration for `WFTQFunctor Set'
I appreciate that QuantifiedConstraint is a fib. I might have instance {-# OVERLAPPING #-} WFT (Set (b -> c)) for which Eq does not hold; but I don't; and/or at least if I use a Set element for which Eq holds, I'll get away with it(?)
But no:
*> wftQfmap toUpper mySet -- mySet :: Set Char
<interactive>:2:1: error:
* Could not deduce (Eq b) arising from a use of `wftQfmap'
from the context: WFT (Set b)
bound by a quantified context at <interactive>:2:1-22
Possible fix: add (Eq b) to the context of a quantified context
* In the expression: wftQfmap toUpper mySet
In an equation for `it': it = wftQfmap toUpper mySet
So why does that instance WFTQFunctor Set compile? And can it ever do anything useful?
OK I have something working. It's ugly and clunky, and not scalable, but answers the q as put:
class WFT c_a where
isWF :: c_a -> Bool -- is c_a well-formed?
mkWF :: c_a -> c_a -- edit c_a to make it well-formed
mkWF = id
instance Eq a => WFT (Set a) -- instance types same as q
isWF NilSet = True
isWF (ConsSet x xs) = not (sElem x xs) && isWF xs -- sElem decl'd in the q
mkWF = fmapSet id -- fmapSet also
class WFTFunctor f where -- class as decl'd in the q
wftfmap :: (WFT (f a), WFT (f b)) => (a -> b) -> f a -> f b
instance WFTFunctor Set where wftfmap f xss = mkWF $ fmap f xss
instance Functor Set where -- conventional/unconstrained fmap
fmap f NilSet = NilSet
fmap f (ConsSet x xs) = ConsSet (f x) (fmap f xs)
If I'm using fmap, generalise:
class Functor f => WFTFunctor f where
wftfmap :: (WFT (f a), WFT (f b)) => (a -> b) -> f a -> f b
wftfmap f xss = mkWF $ fmap f xss
This is not far off H2010 compliant. (Needs FlexibleConstraints.) So I can get the Eq constraint effective 'inside' the WFTFunctor instance; it needs a method call from WFT to pull it through.
I could have heaps of other methods in class WFT, but I say "not scalable" because you couldn't in general 'edit' an ill-formed structure to well-formed. Hmm since it's a Functor: could unload to a List then load back to the structure.

Are extensible GADTs a viable solution to the expression problem?

Consider the following wishful program.
{-# LANGUAGE ExtensibleGADTs #-}
data Free a where
Lift :: a -> Free a
data Free (f a) => FreeFunctor f a where
Map :: (a -> b) -> FreeFunctor f a -> FreeFunctor f b
instance Functor (FreeFunctor f) where
fmap = Map
data FreeFunctor f a => FreeApplicative f a where
Apply :: FreeApplicative f (a -> b) -> FreeApplicative f a -> FreeApplicative f b
Pure :: a -> FreeApplicative f a
instance Applicative (FreeApplicative f) where
(<*>) = Apply
pure = Pure
data FreeApplicative m a => FreeMonad m a where
Bind :: FreeMonad m a -> (a -> FreeMonad m b) -> FreeMonad m b
instance Monad (FreeMonad m) where
(>>=) = Bind
This would introduce a notion of substitutability. For example, a FreeApplicative f a can be substituted by a FreeFunctor f a but not a FreeMonad f a. Similarly, a FreeApplicative f a -> Int can be substituted by a FreeMonad f a -> Int but not a FreeFunctor f a -> Int.
The notion of subtyping can be captured using injections.
import Unsafe.Coerce
fromFreeToFreeFunctor :: Free (f a) -> FreeFunctor f a
fromFreeToFreeFunctor = unsafeCoerce
fromFreeFunctorToFreeApplicative :: FreeFunctor f a -> FreeApplicative f a
fromFreeFunctorToFreeApplicative = unsafeCoerce
fromFreeApplicativeToFreeMonad :: FreeApplicative m a -> FreeMonad m a
fromFreeApplicativeToFreeMonad = unsafeCoerce
The compiler would insert these injections as and where required.
I think that this is a good solution to the expression problem. However, the general consensus is that subtype polymorphism would be problematic in Haskell. So, my question is two fold.
Would subtyping, as I described above, be problematic or interfere with type inference in Haskell?
Would extensible GADTs be a viable solution to the expression problem in Haskell?
I haven't defined a precise semantics for extensible GADTs yet. If this seems like something worth pursuing then I'd like to write a GHC extension for this. Just wanted to put this idea out in the wild and get some criticism.

Matching higher-kinded types in SYB

In general, I'm wondering if there's a way to write a generic fold that generalizes a function that applies a forall type like:
f :: forall a. Data (D a) => D a -> b
given some datatype D for which instance Data (D a) (possibly with constraints on a). To be concrete, consider something even as simple as False `mkQ` isJust, or generally, a query on the constructor of a higher-kinded datatype. Similarly, consider a transformation mkT (const Nothing) that only affects one particular higher-kinded type.
Without explicit type signatures, they fail with No instance for Typeable a0, which is probably the monomorphism restriction at work. Fair enough. However, if we add explicit type signatures:
t :: GenericT
t = mkT (const Nothing :: forall a. Data a => Maybe a -> Maybe a)
q :: GenericQ Bool
q = False `mkQ` (isJust :: forall a. Data a => Maybe a -> Bool)
instead we are told that the forall type of the outer signatures are ambiguous:
Could not deduce (Typeable a0)
arising from a use of ‘mkT’
from the context: Data a
bound by the type signature for:
t :: GenericT
The type variable ‘a0’ is ambiguous
I can't wrap my head around this. If I'm really understanding correctly that a0 is the variable in t :: forall a0. Data a0 => a0 -> a0, how is it any more ambiguous than in say mkT not? If anything, I would've expected mkT to complain because it is the one that interacts with isJust. Additionally, these functions are more polymorphic than the branching on concrete types.
I'm curious to know if this is a limitation of proving the inner constraint isJust :: Data a => ... — my understanding is that any type of instance Data inhabited with Maybe a must also have Data a to be valid by the instance constraint instance Data a => Data (Maybe a).
tldr: You need to create a different function.
mkT has the following signature:
mkT :: (Typeable a, Typeable b) => (a -> a) -> (b -> b)
And you want to apply it to a polymorphic function of type (forall x. Maybe x -> Maybe x). It is not possible: there is no way to instantiate a in (a -> a) to obtain (forall x. Maybe x -> Maybe x).
It's not just a limitation of the type system, the implementation of mkT wouldn't support such an instantiation either.
mkT simply compares concrete types a and b for equality at run time. But what you want is to be able to test whether b is equal to Maybe x for some x. The logic this requires is fundamentally more involved. But it is certainly still possible.
Below, mkT1 first matches the type b against the App pattern to know whether b is some type application g y, and then tests equality of g and f:
{-# LANGUAGE ScopedTypeVariables, RankNTypes, TypeApplications, GADTs #-}
import Type.Reflection
-- N.B.: You can add constraints on (f x), but you must do the same for b.
mkT1 :: forall f b. (Typeable f, Typeable b) => (forall x. f x -> f x) -> (b -> b)
mkT1 h =
case typeRep #b of
App g y ->
case eqTypeRep g (typeRep #f) of
Just HRefl -> h
_ -> id
_ -> id
Compilable example with mkQ1 as well:
{-# LANGUAGE ScopedTypeVariables, RankNTypes, TypeApplications, GADTs #-}
import Type.Reflection
mkT1 :: forall f b. (Typeable f, Typeable b) => (forall x. f x -> f x) -> (b -> b)
mkT1 h =
case typeRep #b of
App g y ->
case eqTypeRep g (typeRep #f) of
Just HRefl -> h
_ -> id
_ -> id
mkQ1 :: forall f b q. (Typeable f, Typeable b) => (forall x. f x -> q) -> (b -> q) -> (b -> q)
mkQ1 h =
case typeRep #b of
App g y ->
case eqTypeRep g (typeRep #f) of
Just HRefl -> const h
_ -> id
_ -> id
f :: Maybe x -> String
f _ = "matches"
main :: IO ()
main = do
print (mkQ1 f (\_ -> "doesn't match") (Just 3 :: Maybe Int)) -- matches
print (mkQ1 f (\_ -> "doesn't match") (3 :: Int)) -- doesn't match

Haskell: apply a polymorphic function twice

We can have a polymorphic function f :: a -> b implemented for different pairs of a and b. How can we make
twice :: (a -> b) -> a -> c
twice f x = f (f x)
type check? i.e. how can I write a function which applies a polymorphic function twice?
With Rank2Types we can get a bit closer but not quite there:
{-# LANGUAGE Rank2Types #-}
twice1 :: (forall a. a -> (m a)) -> b -> (m (m b))
twice1 f = f . f
twice2 :: (forall a. m a -> a) -> m (m b) -> b
twice2 f = f . f
so then some polymorphic functions can be applied twice:
\> twice1 (:[]) 1
[[1]]
\> twice2 head [[1]]
1
Can we go further?
The question was asked over Haskell cafe 10 years ago but wasn't quite answered (with type classes it becomes a lot of boilerplate).
{-# LANGUAGE TypeFamilies, RankNTypes, UnicodeSyntax #-}
type family Fundep a :: *
type instance Fundep Bool = Int
type instance Fundep Int = String
...
twice :: ∀ a . (∀ c . c -> Fundep c) -> a -> Fundep (Fundep a)
twice f = f . f
Now, that won't be much use actually because you can't define a (meaningful) polymorphic function that works with any c. One possibility is to toss in a class constraint, like
class Showy a where
type Fundep a :: *
showish :: a -> Fundep a
instance Showy Bool where
type Fundep Bool = Int
showish = fromEnum
instance Showy Int where
type Fundep Int = String
showish = show
twice :: ∀ a b . (Showy a, b ~ Fundep a, Showy b) =>
(∀ c . Showy c => c -> Fundep c) -> a -> Fundep b
twice f = f . f
main = print $ twice showish False
You can't make twice generic enough even in a dependently typed setting, but it's possible with intersection types:
twice :: (a -> b /\ b -> c) -> a -> c
twice f x = f (f x)
Now whenever f :: a -> b and f :: b -> c typecheck, twice will typecheck too.
There is also a beautiful spell in Benjamin Pierce's thesis (I changed the syntax slightly):
self : (A /\ A -> B) -> B
self f = f f
So self-application is typeable with intersection types as well.

Type Class Data Types

Having read the article Scrap your type classes, I re-implemented some of the ideas shown.
While doing that I came across something really strange: The Type Class - Type can be used as a type constraint! My question: Why is that?
My Code:
{-# LANGUAGE Rank2Types #-}
data IFunctor f = IFunctor {
_fmap :: forall a b. (a -> b) -> f a -> f b
}
-- this type checks...
_fmap2 :: IFunctor f => (a -> b) -> f (f a) -> f (f b)
_fmap2 = \inst -> _fmap inst . _fmap inst
In GHCi the following thing happens:
>>> :t _fmap2 :: IFunctor f => (a -> b) -> f (f a) -> f (f b)
_fmap2 :: IFunctor f => (a -> b) -> f (f a) -> f (f b)
:: IFunctor f -> (a -> b) -> f (f a) -> f (f b)
This doesn't work on GHC 7.8.2. It gives the error Expected a constraint, but ‘IFunctor f’ has kind ‘*’.
Older versions of GHC had a bug where they allowed => to be used like -> in certain situations. This is likely because internally type class constraints are passed as arguments in the form of method dictionaries.

Resources