Switch order of arguments for instance declaration in Haskell - haskell

I want to make an instance declaration, but the free type variable is not the last variable. For example, I have a class declaration
class Poppable m where
tryPop :: m a -> Maybe (a, m a)
Now I want to make Q.PSQ (priority queue) an instance of Poppable. Specifically I want something like this:
instance (Ord p) => Poppable (\a -> Q.PSQ a p) where
tryPop = fmap (first Q.key) . Q.minView
However, this is not legal Haskell code. If the order of arguments to PSQ were switched, then I would have no problem:
instance (Ord p) => Poppable (Q.PSQ p) where
tryPop = fmap (first Q.key) . Q.minView
How do I switch the order of arguments for the instance declaration?
Now I could wrap PSQ with a newtype:
newtype PSQ'' a b = PSQ'' (Q.PSQ b a)
However this seems clunky to me because I have to constantly wrap/unwrap it. Is there an easier way?
*
I tried using data/type families, but both give errors.
(1) Using a data family declaration:
data family PSQ' a b
data instance PSQ' a b = PSQ b a
instance (Ord p) => Poppable (PSQ' p) where
tryPop = fmap (first Q.key) . Q.minView
However this gives the error
Couldn't match type `Q.PSQ a p0' with `PSQ' p a'
even though they can match by setting p=p0.
(2) Type families won't work either.
type family PSQ' a b where
PSQ' b a = Q.PSQ a b
gives
Illegal type synonym family application in instance: PSQ' p

Now I could wrap PSQ with a newtype:
newtype PSQ'' a b = PSQ'' (Q.PSQ b a)
However this seems clunky to me because I have to constantly wrap/unwrap it. Is there an easier way?
Nope, not really. You could, of course, write your Poppable class to make it match PSQ. And if you like, you can generalize your newtype to
newtype Flip f a b = Flip (f b a)
at which point you could write
instance Poppable (Flip Q.PSQ a)
but none of this will get rid of the underlying annoyance factor. There are reasons Haskell doesn't support this (apparently, it makes inference much harder, sometimes impossible, etc.), so you'll just have to deal with it.
P.S., that type synonym may be more useful poly-kinded, with {-# LANGUAGE PolyKinds #-}, where it ends up meaning
newtype Flip (f :: k1 -> k2 -> *) (a :: k2) (b :: k1) = Flip (f b a)

You could simply abandon parametricity and use a type family to project whichever argument correspond to the 'element type':
class Poppable q where
type Elem q
tryPop :: q -> Maybe (Elem q, q)
data PSQ a p = ...
instance Ord p => Poppable (PSQ a p) where
type Elem (PSQ a p) = a
tryPop = ...
Note this is a more general formulation, but it may be harder to work with.

Related

Enforcing parametricity on arguments

Using RankNTypes one can enforce various kinds of parametricity. For example, A id :: A:
newtype A = A { unA :: forall a. a -> a }
But how about cases where we only care about the parametricity of the function on its argument? For a specific kind of case, the following will work:
newtype X b = X { unX :: forall a. a -> (a, b) }
For example, X (\a -> (a, ())) :: X ().
I would like to understand how to (or whether one can) construct a parametricity test that works more generally for functions of the form \a -> (a, f a), where f may be constant (as above) or potentially parametric itself. This can't be accomplished with X. E.g., X (\a -> (a, id a)) is a type error. Can this be done?
Edit: I'd like to repose or elaborate on the question somewhat. Suppose we have a type of parameterized state transformers:
type PState i o a = i -> (a, o)
Suppose also that we are interested in statically enforcing that the a in an arbitrary m :: PState i o a does not depend on i in any way. In other words, is it possible to define a function f such that f m is well typed when m's value doesn't depend on the input (and in that case evaluates to m), and is not well typed otherwise?
You'll need to make an explicit type-level function to accomplish this. Normally quantified Type -> Type variables are actually assumed to be type constructors (injective functions), which is not sufficient here. But it is possible to have noninjective ones too, they're just called type families. The flip side to this is that you need some separate means of actually indexing which one you want, because type inference wouldn't work without that.
{-# LANGUAGE TypeFamilies, KindSignatures, EmptyDataDecls, TypeInType
, RankNTypes, UnicodeSyntax #-}
import Data.Kind
type family MyTyFun (f :: Type) (a :: Type) :: Type
newtype GState f = GState { unGS :: ∀ a . a -> (a, MyTyFun f a) }
data Af
type instance MyTyFun Af a = ()
type A = GState Af
data Xf b
type instance MyTyFun (Xf b) a = b
type X b = GState (Xf b)
data Wf
type instance MyTyFun Wf a = a
type W = GState Wf
> unGS (GState (\a -> (a, a)) :: W) 4
(4,4)

How can I pass a monadic function as an argument with a flexible type variable?

Apologies for the potentially vague question title - I'm not sure how to phrase it because I have a pretty poor understanding of what the problem is.
Basically, how do I make the following compile? :-p
{-# LANGUAGE MultiParamTypeClasses #-}
class (Monad m) => MyClass m a where
valM :: m (Maybe a)
val :: m a
f :: (MyClass m a) => (m a -> IO a) -> IO (a, Maybe a)
f g = do
x <- g val
yM <- g valM
return (x, yM)
GHC (v8.2.2) complains that a is a rigid type variable and can't seem to cope with the idea that (g val) and (g valM) could produce values of different types. I've tried using RankNTypes but to no avail.
Is there an extension I can use to help the compiler, or is there something conceptually broken with what I'm trying to do from a type-inference point of view?
You’re right that you need RankNTypes, but you’re missing a forall. The correct type for f is:
f :: MyClass m a => (forall b. m b -> IO b) -> IO (a, Maybe a)
…since the function passed to f must work for any result type, and it shouldn’t be related to the a in the result.
It’s also potentially worth noting that this sort of function is also known as a natural transformation, and the natural-transformation package provides a (~>) type alias for such functions:
type (~>) f g = forall a. f a -> g a
Therefore, using that type alias, you could also write f like this:
f :: MyClass m a => (m ~> IO) -> IO (a, Maybe a)

How to coerce functors applied to coercible arguments

Consider the following Haskell code:
import Data.Coerce
newtype Decorated s a = Decorated a
fancyFunction :: Ctx s => f (Decorated s a) -> r
fancyFunction = ...
instance Ctx s => SomeClass (Decorated s a)
myFunction :: Functor f => f a -> r
myFunction = fancyFunction . fmap coerce
I'd like to make myFunction faster by replacing fmap coerce with coerce. The rationale is that coerce behaves like id and one of the functor laws is fmap id = id.
The only way I can see of doing this is to add Coercible (f a) (f (Decorated s a)) to the context but it refers to s which is not referred to anywhere else. Even worse, if a is bound in a universal type, I cannot express the constraint. Is there a constraint I could express in terms of f only to let me use coerce to convert between f a and f (Decorated s a)?
Is this something that the compiler figures out on its own from the fact that f is a functor? If so, does it also work with bifunctors, traversables and bitraverables?
Unfortunately, Coercible (f a) (f (Decorated s a)) really what you want in your constraint given the current state of GHC. Now, the fact that s and a don't show up elsewhere is not something good - it means GHC won't know what to do with them (they are ambiguous)! I won't get into that...
Depending on the role of the type parameter fed to the type constructor f, Coercible a b may or may not imply Coercible (f a) (f b). In this case, we'd want that role to be nominal - but there isn't (yet at least) a way to express this in a constraint. To explain what I mean, consider the following two data definitions:
{-# LANGUAGE TypeFamilies #-}
import Data.Coerce
-- type role of `a` is "representational"
data Data1 a = Data1 a
-- type role of `a` is "nominal"
data Data2 a = Data2 (TypeFunction a)
type family TypeFunction x where
TypeFunction Bool = Char
TypeFunction _ = ()
Then, while it is true that Coercible a b entails Coercible (Data1 a) (Data1 b), it does not entail Coercible (Data2 a) (Data2 b). To make this concrete, load up the above in GHCi, then try:
ghci> newtype MyInt = My Int
ghci> let c1 = coerce :: (Data1 MyInt) -> (Data1 Int)
ghci> let c2 = coerce :: (Data2 MyInt) -> (Data2 Int) -- This doesn't work!
Unfortunately, there is no built-in constraint based way of enforcing that the role of a type variable is representational. You can make your own classes for this, as Edward Kmett has done, but GHC doesn't automatically create instances of some of these classes the way class instances for Coercible are.
This led to this trac ticket where they discuss the possibility of having a class Representational f with instances generated like for Coercible which could have things like
instance (Representational f, Coercible a b) => Coercible (f a) (f b)
If this was actually a thing today, all you would need in your constraint would be Representational f. Furthermore, as Richard Eisenberg observes on the ticket, we really ought to be able to figure out that a in f a has a representational role for any reasonable functor f. Then, we might not even need any constraint on top of Functor f as Representational could be a superclass of Functor.
Here is a good discussion of the current limitations of roles.
Now that you have QuantifiedConstraints, I think you can do this:
type Parametric f = (forall a b. (Coercible a b => Coercible (f a) (f b)) :: Constraint)
newtype Foo = Foo Int
myFunction :: (Parametric f) => f Foo -> f Int
myFunction = coerce
test :: [Int]
test = myFunction [Foo 1, Foo 2, Foo 3]
This is nice, because an instance of Parametric f witnesses that f is an endofunctor on a category where the objects are types and a morphism between types A and B is an instance of Coercible A B.

Can a function be parametrically polymorphic over a non-nullary type constructor?

In Haskell, there are many examples of higher kinded polymorphism when dealing with ad hoc polymorphism, such as Monad and Functor. However, I cannot think of any examples of this for parametric polymorphism.
Is this possible, and if so, can I have an example of one which is useful?
If you still allow typeclass constraints, then the answer is, sure! E.g. I'd still call something like
normalise :: (Foldable f, Functor f, Fractional n) => f n -> f n
normalise v = fmap (/sum v) V
parametric polymorphism. But I suppose that's not what you have in mind.
Another thing that's obviously possible is to just contrain types to have a particular form _ _, like
hmap :: (f a -> f b) -> [f a] -> [f b]
hmap = map
This isn't exactly remarkable, but it could possibly be useful in some applications as a subtle hint to the type checker. In fact, this is one way you can solve the phantom argument problem: instead of
class LengthyList l where minimumLength :: l a -> Int
instance LengthyList [] where minimumLength _ = 0
instance LengthyList NonEmpty where minimumLength _ = 1
you might make the signature
minimumLength :: p (l a) -> Int
aka
minimumLength :: proxy (l a) -> Int
Thereby you still pass in the type-information of l, but guarantee that the implementation cannot try to evaluate the argument at runtime.
The standard way to do this is however
minimumLength :: Tagged (l a) Int
or
minimumLength :: Proxy (l a) -> Int
Generally though, there's nothing you could do with f a that couldn't also be done with fa, so essentially you could rewrite the type of any such higher-order parametric function to a first-order parametrically polymorphic one.
You totally can do this. A type synonym pigworker is fond of:
type f ~> g = forall a . f a -> g a
This, for reasons I don't actually know, represents a natural transformation (whatever exactly that is) between functors f and g. But a function can take an argument of type f ~> g and apply it to as many types f a as it likes. Using non-regular types (specifically, higher-order nested data types, as Ralf Hinze, for example, explored in Numerical Representations as Higher-Order Nested Datatypes), it could be applied to an unbounded number of different types.
A contrived example:
{-# LANGUAGE RankNTypes, TypeOperators #-}
type f ~> g = forall a . f a -> g a
data Two g a = Two (g a) (g a)
data Foo f a = This (f a)
| That (Foo (Two f) a)
hello :: (f ~> g) -> Foo f a -> Foo g a
hello t (This fa) = This (t fa)
hello t (That buh) =
That (hello (\(Two x y) -> Two (t x) (t y)) buh)
hello is polymorphic in the types f and g, each of which has kind * -> *. † I believe that converting this to use only types of kind * could require non-trivial refactoring.
†In fact, if you enable PolyKinds, f and g will each have a polykinded type k -> *.
One example I'm quite fond of is the foldr operator for lists indexed by their length: it is parametrically polymorphic over a predicate p of kind Nat -> * and guarantees that if you apply it to a list of length m then you get back a proof of p m.
This corresponds to this type:
foldr :: forall a (p :: Nat -> *).
(forall n. a -> p n -> p ('Succ n)) ->
p 'Zero ->
forall n. Vec a n -> p n
This extra precision makes it possible to implement e.g. append using foldr rather than having to proceed by pattern-matching.
append :: forall a m n. Vec a m -> Vec a n -> Vec a (m :+: n)
I've uploaded a complete gist with all the right language extensions turned on and the code corresponding to these types in case you want to peek.

Typeclasses 101: GHC too "eager" to derive instance?

Given the following code:
class C a where
foo :: a -> a
f :: (C a) => a -> a
f = id
p :: (C a) => (a -> a) -> a -> a
p g = foo . g
Now, if I try to invoke p f, GHC complains:
> p f
No instance for (C a0) arising from a use of `p'
In the expression: p f
In an equation for `it': it = p f
I find that somewhat surprising, since f only accepts an "a" which has to be an instance of the typeclass C. What is the reason?
Edit: I know I did not define any instance for C but shouldn't the "proper" response be:
p f :: (C a) => a -> a
When you put a plain expression into ghci, it is basically trying to print it, so
> p f
is approximately the same as having the following in a file
main :: IO ()
main = print $ p f
As you pointed out, p f :: (C a) => a -> a. In order to print $ p f GHC needs to evaluate p f. GHC cannot evaluate a value with a type class context without choosing a dictionary to pass in. To do so, it needs to find a C a instance for all a, which doesn't exit. It also needs to find a Show instance for a -> a. The inability to find either of these results in two errors
No instance for (Show (a -> a)) arising from a use of `print'
No instance for (C a) arising from a use of `p'
It's the dreaded monomorphism restriction in action. By default, GHC doesn't allow us to have top-level value definitions without type annotations if the inferred type has a class constraint. You can remedy the situation by
a.) Turning the restriction off by adding {-# LANGUAGE NoMonomorphismRestriction #-} to the top of your source.
b.) Adding type annotations to affected top-level bindings:
foo :: C a => a -> a
foo = p f
c.) Expanding function definitions (if possible):
foo x = p f x

Resources