more rmonad libraries? - haskell

I want to do some rudimentary things with RMonad. Are there ways of using the "as monad" functionality to
have an identity rmonad, to apply monad transformers to?
have common things like StateT transformers?
add a constraint to an existing monad? (e.g. if one wanted a StateT with additional constraints)
unfortunately I haven't yet grasped things like data families, etc. that make it work ... otherwise I'd probably be happy to write the code myself.
edit
I hacked StateT together from library sources, will see if it works ...
[ http://pastebin.com/VT3uyEgr ]

Your version of StateT looks correct after a quick glance. Unfortunately, using RMonad et. al. does require duplicating just about everything; I started doing writing some code using Suitable and gave up because it involved too much duplication (and in the end I didn't really need it).
Edit:
From my memory of how Suitable works, it's something like this:
Consider the Functor class: Set can't be an instance of it because it needs the extra Ord constraint.
A naive approach would be something like:
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
import qualified Data.Set as S
class MyFunctor c a | c -> a where
myfmap :: (MyFunctor c b) => (a -> b) -> c a -> c b
instance (Ord a) => MyFunctor S.Set a where
myfmap = S.map
But this then returns the following error:
Error: test.hs:11:16: Could not deduce (Ord b) arising from a use of `S.map'
from the context (Ord a)
bound by the instance declaration at /tmp/test.hs:10:10-37
or from (MyFunctor S.Set b)
bound by the type signature for
myfmap :: MyFunctor S.Set b => (a -> b) -> S.Set a -> S.Set b
at /tmp/test.hs:11:7-20
Possible fix:
add (Ord b) to the context of
the type signature for
myfmap :: MyFunctor S.Set b => (a -> b) -> S.Set a -> S.Set b
or the instance declaration
In the expression: S.map
In an equation for `myfmap': myfmap = S.map
In the instance declaration for `MyFunctor S.Set a'
Why is this? It's because the constraint isn't kept or found at the instance level, so GHC doesn't realise that when using myfmap, there should be an Ord constraint on b.
The Suitable type is used to explicitly create a constraint dictionary which allows you to specify these kinds of constraints:
import Data.Suitable
import qualified Data.Set as S
class MyFunctor c where
myfmap :: (Suitable c a, Suitable c b) => (a -> b) -> c a -> c b
instance MyFunctor S.Set where
myfmap f s = withConstraintsOf s
$ \ SetConstraints
-> withResConstraints $ \ SetConstraints -> S.map f s
(where SetConstraints is already defined in Data.Suitable)
This implementation works, but it does make type signatures a bit more convoluted, and method implementations a bit hairier (note here that we need to bring in SetConstraints twice: once for the Set a, the other for the Set b). Note that for types without any constraints, none of the Suitable constraint functions are needed.
I had started to try and create Suitable versions of the classes in the Typeclassopedia but gave up because the instances were getting rather hairy.

Related

Quantified Constraints for Higher-kinded Typeclasses

Suppose I would like to write two Typeclasses.
Header:
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE UndecidableInstances #-}
import Data.Complex
The first typeclass ExClass was defined as such:
class (forall a. (Monoid (t a))) => ExClass t where
exFunc :: [t (Complex a)] -> t (Complex a)
exFunc = mconcat -- the actual function is more complicated
exFunc2 :: (RealFloat a) => t (Complex a) -> a
I defined it as a higher-kinded typeclass because one of its functions' output type depends on the type of its nested value a. I would also like to have a default implementation for exFunc, but it involves the assumption that t a is a Monoid. Now I would like to write an instance for the following type:
newtype ExType a = ExType a
ExType a is a Monoid only when Num a is true:
instance (Num a) => Semigroup (ExType a) where
ExType a <> ExType b = ExType (a * b)
instance (Num a) => Monoid (ExType a) where
mempty = ExType 1
Now I go on to define the typeclass instance for ExClass, specifying the constraint of Num a:
instance (forall a. Num a) => ExClass ExType where
exFunc2 (ExType a) = magnitude a
The above code will compile with no problem. However, if I were to try to use the implemented function like so:
x = ExType 2 :: ExType (Complex Double)
func = exFunc2 x
I receive the following complaint:
• No instance for (Num a) arising from a use of ‘exFunc2’
Possible fix: add (Num a) to the context of a quantified context
• In the expression: exFunc2 x
In an equation for ‘func’: func = exFunc2 x
This also happens when I use a different instance declaration:
instance (forall a. Monoid(ExType a)) => ExClass ExType where
exFunc2 (ExType a) = magnitude a
Is there a way to make this typeclass work? or am I just not supposed to structure my program like this at all?
Daniel Wagner has already explained in his answer the problems with the current definition.
It seems that you want ExClass to mean something like "a class of container types that have a special relationship with another class c applied to their elements, and when their elements satisfy c, the containers themselves are monoids".
For example: ExType has a special relationship with Num. When the elements a of ExType satisfy Num, ExType a becomes a Monoid.
(This is already affirmed in ExTypes Monoid instance, but it seems you want to express it with a higher level of abstraction; to have a class for those containers that become monoids in a similar way.)
In Haskell, there are various possible ways to express a relationship between two types—or between a type and a Constraint. Let's use MultiParameterTypeClasses:
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ConstraintKinds #-}
import Data.Kind (Type, Constraint)
-- This kind signature is not strictly required, but makes things clearer
type ExClass :: (Type -> Constraint) -> (Type -> Type) -> Constraint
class (forall a . c a => Monoid (t a)) => ExClass c t | t -> c where
exFunc :: c a => [t a] -> t a
exFunc = mconcat
Notice that ExClass has now two parameters, and that the type f of the container determines (through a functional dependency) the constraint c that is required of the elements of f for f to be a Monoid. c might be different for different fs!
The Semigroup and Monoid instances for ExType don't change. The ExClass instance for ExType would now be:
instance ExClass Num ExType where
exFunc = mconcat
Putting it to work:
main :: IO ()
main = print $ exFunc [ExType (1::Int), ExType 2]
(I have left out the Complex datatype, which might throw another wrench in the definition.)
I think there's a couple reasoning errors going on here at once.
First: when you write
class (forall a. Monoid (t a)) => ExClass t
this means that if somebody wants to implement an ExClass t instance, then they must show that there is an instance of the form instance Monoid (t a) where ... with no constraints whatsoever on a. Note also that it is not enough for there to be instances for all possible choices of a -- the instance itself must be parametric.
Second: when you write
instance (forall a. Num a) => ExClass ExType
there is no magical connection between the a mentioned here and the a mentioned in the definition of ExClass.
Third: when you write
instance (forall a. Num a) => ExClass ExType
this doesn't actually make an instance of ExClass ExType yet. It makes an instance conditioned on a proof that forall a. Num a. In general, the meaning of instance Ctx => C t is that anybody who wants to assume the fact C t must be able to themselves prove Ctx. Nobody's going to reasonably be able to show forall a. Num a, so this instance is unusable.
These last two comments apply essentially unchanged to your second attempt,
instance (forall a. Monoid(ExType a)) => ExClass ExType
Unfortunately, without more details on what you're trying to do and why, it's nigh-on impossible to suggest the right route forward. Possibilities include an indexed-monad-like approach, moving the class constraint from the class context to various method contexts, not making a class at all, and more.
I would also like to have a default implementation for exFunc, but it involves the assumption that t a is a Monoid
You only require Monoid (t a) in order to have a default implementation? That's backwards. If that constraint isn't conceptually required as a superconstraint for ExClass, then it shouldn't be in the class head.
You can still have a default implementation that is more restrictive:
{-# LANGUAGE DefaultSignatures #-}
class ExClass t where
exFunc :: [t (Complex a)] -> t (Complex a)
default exFunc :: Monoid (t (Complex a)) => [t (Complex a)] -> t (Complex a)
exFunc = mconcat
exFunc = mconcat -- the actual function is more complicated
exFunc2 :: (RealFloat a) => t (Complex a) -> a
And then simply
instance ExClass ExType where
exFunc2 (ExType a) = magnitude a
You would still also be able to provide instances that don't fulfill the Monoid constraint at all, you just then would need to manually implement exFunc too.
Even simpler is to not bother with default implementations at all, but just provide a helper that can be used to get a simple implementation without duplicating any code:
class ExClass t where
exFunc :: [t (Complex a)] -> t (Complex a)
exFunc = mconcat -- the actual function is more complicated
exFunc2 :: (RealFloat a) => t (Complex a) -> a
monoidIshExFunc :: Monoid (t (Complex a)) => [t (Complex a)] -> t (Complex a)
monoidIshExFunc = mconcat
instance ExClass ExType where
exFunc = monoidIshExFunc
exFunc2 (ExType a) = magnitude a
(monoidIshExFunc could even require ExClass t, just obviously you should be careful to not end up in a circular definition!)

Letting a distributed DSL implementation choose its serialization format (via constraint family)

I'm writing a distributed programming DSL and I'd like to allow implementations to choose their serialization method (if any, as it might not even be needed for a simulated execution).
Trying to solve this by adding a type family led to the problem below for a standard function I have. I imagine that it would work if I could require, and have the type checker understand, that if two values are serializable their pairing is also serializable. However, adding that as a quantified constraint doesn't seem to work. Can this be solved or is there a better solution for the problem?
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
import Data.Kind
class (Monad (DistrM t)) => Distributed (t :: *) where
type Sendable t :: * -> Constraint
type DistrM t :: * -> *
-- ...
data FromSendable t a where
FromSendable :: (Sendable t b)
=> (b -> DistrM t a)
-> b
-> FromSendable t a
pairWith :: ( Sendable t a
, Distributed t
, forall a b. (Sendable t a, Sendable t b) => Sendable t (a,b)
)
=> a
-> FromSendable t b
-> FromSendable t (a,b)
pairWith a (FromSendable f b) =
FromSendable (\(a,b) -> (a,) <$> f b) (a,b)
-- >>> Could not deduce: Sendable t (a1, b1) ...
Edit 1
It type checks if I do
pairWith :: ( Sendable t a
, Distributed t
, st ~ Sendable t
, forall a b. (st a, st b) => st (a,b)
)
=> ...
It would get cumbersome to have to repeat these types of constraints, so I tried a type synonym but that doesn't work:
type Cs t = forall (st :: * -> Constraint).
(Sendable t ~ st, forall a b. (st a, st b) => st (a,b))
-- >>> Expected a constraint, but ‘st (a, b)’ has kind ‘*’
This looks weird. I only have a partial answer, but I'll post it anyway.
I simplified your code to
class C t where -- (*)
data T t where
T :: C t => (a -> t) -> a -> T t
foo ::
( C u
, forall a b . (C a , C b) => C (a, b) )
=> u -> T t -> T (u, t)
foo i (T f x) = T (\(a,b) -> (a, f b)) (i, x)
and, in this version, it compiles fine. However, if we replace
class C t where
with
type instance C :: * -> Constraint
then we get an error telling us that C (a, b) can not be deduced.
I can't completely understand what's going on here, but it looks like quantified constraints do not mix well with type families.
It looks like the above type family is treated like it were
type instance C (t :: *) :: Constraint
and in such case, I can't understand what's wrong. Since C now does not refer to a single type class, it is impossible to implement a quantified constraint like forall a b . (C a , C b) => C (a, b) by (say) passing a pointer to a specific instance, since the three C constraints could be anything at all, in an open world.
I still do not understand why type family C :: * -> Constraint is handled in the same way.
Perhaps GHC should reject quantified constraints involving type families ... -> Constraint in such way? I not sure.
I think you've pushed your code to the edges of GHC's type system here. You can fix the kind error on Cs by writing:
type Cs t = (forall (st :: * -> Constraint).
(Sendable t ~ st, forall a b. (st a, st b) => st (a,b))) :: Constraint
but then you run up against "GHC doesn't yet support impredicative polymorphism". Until GHC adds support for class families as per issue 14860, you're maybe out of luck with this approach.
However, you did ask about alternative approaches. Doesn't making Sendable t a a multiparameter type class accomplish basically the same thing?
Certainly, the following type-checks:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
import Data.Kind
class (Monad (DistrM t)) => Distributed (t :: *) where
type DistrM t :: * -> *
-- ...
class Sendable t a where
data FromSendable t a where
FromSendable :: (Sendable t b)
=> (b -> DistrM t a)
-> b
-> FromSendable t a
type Cs t = forall a b. (Sendable t a, Sendable t b) => Sendable t (a,b) :: Constraint
pairWith :: ( Sendable t a
, Distributed t
, Cs t
)
=> a
-> FromSendable t b
-> FromSendable t (a,b)
pairWith a (FromSendable f b) =
FromSendable (\(a,b) -> (a,) <$> f b) (a,b)

Illegal polymorphic or qualified type in typeclass

The following file Poly.hs file
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE RankNTypes #-}
module Poly () where
type ListModifier s = forall a. s -> [a] -> [a]
instance Monoid (ListModifier s) where
mempty = const id
mappend f g st = f st . g st
Gets the typechecker to complain:
Poly.hs:8:10: Illegal polymorphic or qualified type: ListModifier s …
In the instance declaration for ‘Monoid (ListModifier s)’
Compilation failed.
Initially I though it couldn't compose the rank 2 types but:
λ> :t (undefined :: forall a . a -> String ) . (undefined :: forall b . String -> b)
(undefined :: forall a . a -> String ) . (undefined :: forall b . String -> b)
:: String -> String
I feel the Poly module is in some way inherently inconsistent but I can't put my finger on the problem.
ListModifier is a type alias, not a “real” type. Type aliases are essentially macros at the type level, always expanded by the typechecker before actually typechecking. That means your instance declaration is equivalent to the following:
instance Monoid (forall a. s -> [a] -> [a]) where
Even if that were allowed, it would overlap with the existing Monoid (a -> b) instance, so it still wouldn’t work. The larger problem, however, is that you can’t have an instance defined on a forall-quantified type because it wouldn’t make sense from the perspective of instance resolution.
What you could do instead is define a fresh type instead of a type alias using newtype:
newtype ListModifier s = ListModifier (forall a. s -> [a] -> [a])
Now you can define a Monoid instance, since typeclass resolution only needs to look for the ListModifier type, which is much simpler to match on:
instance Monoid (ListModifier s) where
mempty = ListModifier (const id)
mappend (ListModifier f) (ListModifier g) = ListModifier (\st -> f st . g st)
Alternatively, you could keep your type alias and define a newtype with a different name, like ReifiedListModifier, then define an instance on that, and you could only do the wrapping when you need to store a ListModifier in a container or use a typeclass instance.

How to put constraints on type variable of kind `Constraint`?

I'm playing around with the ConstraintKinds extension of GHC.
I have the following data type, which is just a box for things fulfilling some one parameter constraint c:
data Some (c :: * -> Constraint) where
Some :: forall a. c a => a -> Some c
For example, I could construct a box with some kind of number (arguably not very useful).
x :: Some Num
x = Some (1 :: Int)
Now, as long as c includes the constraint Show, I could provide an instance of Show (Some c).
instance ??? => Show (Some c) where
show (Some x) = show x -- Show dictionary for type of x should be in scope here
But how do I express this requirement in the instance context (marked with ???)?
I cannot use an equality constraint (c ~ Show), because the two are not necessarily equal. c could be Num, which implies, but is not equal to, Show.
Edit
I realised that this cannot be possible in general.
If you have two values of type Some Eq, it is not possible to compare them for equality. They could be of different types that each have their own notion of equality.
What applies to Eq applies to any type class in which the type parameter appears on the right hand side of the first function arrow (like the second a in (==) :: a -> a -> Bool).
Considering that there is no way to create a constraint expressing "this type variable is not used beyond the first arrow", I don't think it is possible to write the instance I want to write.
The closest we are able to get is a Class1 class that reifys the relationship between a class and a single superclass constraint as a class. It's based on the Class from constraints.
First, we'll take a short tour of the constraints package. A Dict captures the dictionary for a Constraint
data Dict :: Constraint -> * where
Dict :: a => Dict a
:- captures that one constraint entails another. If we have a :- b, whenever we have the constraint a we can produce the dictionary for the constraint b.
newtype a :- b = Sub (a => Dict b)
We need a proof similar to :-, we need to know that forall a. h a :- b a, or h a => Dict (b a).
Single Inheritance
Actually implementing this for classes with just single inheritance requires the kitchen sink of language extensions, including OverlappingInstances.
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverlappingInstances #-}
import Data.Constraint
We'll define the class of constraints of kind k -> Constraint where the constraint has a single superclass.
class Class1 b h | h -> b where
cls1 :: h a :- b a
We're now equipped to tackle our example problem. We have a class A that requires a Show instance.
class Show a => A a
instance A Int
Show is a superclass of A
instance Class1 Show A where
cls1 = Sub Dict
We want to write Show instances for Some
data Some (c :: * -> Constraint) where
Some :: c a => a -> Some c
We can Show a Some Show.
instance Show (Some Show) where
showsPrec x (Some a) = showsPrec x a
We can Show a Some h whenever h has a single superclass b and we could show Some b.
instance (Show (Some b), Class1 b h) => Show (Some h) where
showsPrec x (Some (a :: a)) =
case cls1 :: h a :- b a of
Sub Dict -> showsPrec x ((Some a) :: Some b)
This lets us write
x :: Some A
x = Some (1 :: Int)
main = print x
The new QuantifiedConstraints extension allows this.
class (a => b) => Implies a b where
instance (a => b) => Implies a b where
instance (forall a. c a `Implies` Show a) => Show (Some c) where
show (Some x) = show x
Within the body of the Show instance, it is as if there is a
instance forall a. Implies (c a) (Show a)
in scope. If you then have T :: Type and know c T, then the superclass of c T => Show T of the specialized Implies (c T) (Show T) instance allows you to derive Show T. It is necessary to use Implies instead of a straight forall a. c a => Show a constraint. This incorrect constraint acts like
instance forall a. c a => Show a
which overlaps with every Show instance, causing weird breakage. Forcing an indirection through the superclass of an otherwise useless constraint fixes everything.
You cannot make Some c an instance of Show, except trivially.
You want to show the a inside Some, but that variable is existentially quantified, so we cannot depend on any knowledge of the type of a. In particular, we have no way of knowing that a is an instance of Show.
EDIT: I'll expand on my answer.
Even with more machinery, and giving up on a Show instance, I still don't think what you want is possible because of the existential quantification.
First I'll rewrite Some in a more familiar form
data Dict p where
Dict :: p a => a -> Dict p
The usual way to talk about "constraints implying constraints" is with the concept of constraint entailment.
data p :- q where
Sub :: p a => Dict q -> p :- q
We can think about a value of type p :- q as a proof that if the constraint forall a. p a holds, then forall a. q a follows.
Now we try to write a sensible show-ish function
showD :: p :- Show -> Dict p -> String
showD (Sub (Dict a)) (Dict b) = show b
At a glance, this might work. We have brought the following constraints into scope (forgive the pseudo-exists syntax)
(0) p :: * -> Constraint
(1) exists a. p a -- (Dict p)
(2) exists b. p b => Show b -- (p :- Show)
But now things fall apart, GHC rightfully complains:
main.hs:10:33:
Could not deduce (Show a2) arising from a use of `show'
from the context (p a)
bound by a pattern with constructor
Sub :: forall (p :: * -> Constraint) (q :: * -> Constraint) a.
(p a) =>
Dict q -> p :- q,
in an equation for `showD'
at main.hs:10:8-19
or from (Show a1)
bound by a pattern with constructor
Dict :: forall (p :: * -> Constraint) a. (p a) => a -> Dict p,
in an equation for `showD'
at main.hs:10:13-18
or from (p a2)
bound by a pattern with constructor
Dict :: forall (p :: * -> Constraint) a. (p a) => a -> Dict p,
in an equation for `showD'
at main.hs:10:23-28
because it is impossible to unify the a from (1) with the b from (2).
This is the same essential idea that is used throughout the constraints package mentioned in the comments.

What is the purpose of the `Typeable (* -> Constraint) Monoid` instance?

Since GHC 7.8, Typeable is poly-kinded. Looking at the list of built-in Typeable instances in the documentation, I noticed something interesting:
Typeable ((* -> *) -> Constraint) Alternative
Typeable ((* -> *) -> Constraint) Applicative
Typeable (* -> Constraint) Monoid
Apparently, it's allowed to look at type representations of (certain) types of kind Constraint:
Prelude Data.Monoid Data.Typeable> typeRep $ (Proxy :: Proxy (Monoid Int))
Monoid Int
Are there any uses for this feature or was it just made available by accident?
Well, ConstraintKinds are now allowed. So this means that you can define datatypes parameterized over constraints.
A (contrived) example:
data CPair (c :: * -> Constraint) where
MkCPair :: (c a, c b) => a -> b -> CPair c
This is a pair of two components of potentially different types that share a common class:
aPair :: CPair Show
aPair = MkCPair 'x' True
Now, do we want aPair to be Typeable? This requires both CPair and Show to
be Typeable as well.
deriving instance Typeable CPair
deriving instance Typeable Show
Now:
GHCi> typeOf aPair
CPair Show
So it's only consequent to derive Typeable for classes if they can appear as types now.
The funny thing is that Typeable Show isn't predefined, but Typeable Applicative is. This is because there's a new GHC extension AutoDeriveTypeable which seems to be enabled in some modules, but not in others. With AutoDeriveTypeable, there are Typeable instances being derived for everything in a module, including classes.

Resources