more rmonad libraries?
-
27-10-2019 - |
Question
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 ...
Solution
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.