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 ...

[ http://pastebin.com/VT3uyEgr ]

Was it helpful?

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top