Can one compose types in a Haskell instance declaration?

I've written a Haskell typeclass and it would be convenient to declare instances of it using types of the form (a -> m _) , where m is of kind (* -> *) , such as a monad, and _ is a slot to be left unsaturated. I know how to write newtype X amb = X (a -> mb) , and declaring an instance for X am . But what I'm looking for is to instead use the bare, unwrapped -> type, if that's possible.

If one wants to declare instances for types of the form (a -> _) , then you can just write:

instance Foo a ((->) a) where ...

but I don't know how/whether one can do it with types of the form (a -> m _) . I guess I'm looking to compose the type constructor (->) a _ and the type constructor m _ in my instance declaration.

I'd like to write something like this:

instance Foo a ((->) a (m :: *->*)) where ...

or:

instance Foo a ((->) a (m *)) where ...

but of course these don't work. Is it possible to do this?

Concretely, here's what I'm trying to achieve. I wrote a typeclass for MonadReaders that are embedded inside (one level) of other MonadReaders, like this:

{-# LANGUAGE FunctionalDependencies FlexibleInstances
UndecidableInstances  #-}

class MonadReader w m => DeepMonadReader w r m | m -> r where
  { deepask   :: m r
  ; deepask = deepreader id
  ; deeplocal :: (r -> r) -> m a -> m a
  ; deepreader :: (r -> a) -> m a
  ; deepreader f = do { r <- deepask; return (f r) }
  }

instance MonadReader r m => DeepMonadReader w r (ReaderT w m) where
  { deepask = lift ask
  ; deeplocal = mapReaderT . local
  ; deepreader = lift . reader
  }

It'd be nice to also provide an instance something like this:

instance MonadReader r m => DeepMonadReader w r ((->) w (m :: * ->
*)) where
  { deepask = w -> ask
  ; deeplocal f xx = w -> local f (xx w)
  ; deepreader xx = w -> reader xx
  }

I think you're on the wrong track and are making things a lot more complicated than they need to be.

Some observations:

... ((->) w (m :: * -> *)) ...

Let's explore what you mean by this. You are using it for the type parameter m in your DeepMonadReader class, and therefore it needs to be a monad. Can you give a concrete example of a monad which has this type? Why not just use ((->) w) ?

class MonadReader wm => DeepMonadReader wrm | m -> r where ...

The fact that w never apears in any member signatures is an indication something is amiss.

... I wrote a typeclass for MonadReaders that are embedded inside (one level) of other MonadReaders ...

I would take the reverse perspective. It makes sense to talk of monad stacks which are a transformed version of another monad stack. Eg:

StateT s (WriterT w IO)   "contains"     IO
WriterT w (Maybe a)       "contains"     Maybe a

And what does it mean for a monad stack m1 to "contain" another monad m2 ? It just means that there is a way to convert computations in m2 to computations in m1 :

convert ::  m2 a -> m1 a

Of course, this is just lift when using monad transformers.

To express your concept of a monad reader embedded in another monad, I would use this type class:

class HasReader m m' r where ...
  deepAsk :: m r
  deepLocal :: (r -> r) -> m' a -> m a

The idea here is that an instance HasReader mm' r expresses the fact that monad m "contains" a monad m' which itself is a reader with environment r .

deepAsk returns the environment of m' but as a computation in m .

deepLocal runs a computation in m' with a environment modification function but returns it as a computation in m . Note how this type signature is different from yours: my deepLocal uses different monads, m' and m whereas yours just goes from m to m .

The next step is decide which triples (m, m', r) do we want to write instances of HasReader for. Clearly it seems you had instances like this in mind:

m                                    m'                           r
---------------------                -----------                  --
ReaderT s (ReaderT r m)              ReaderT r m                  r
ReaderT t (ReaderT s (ReaderT r m)   ReaderT s (Reader T r m)     s
...

but it also seems reasonable to want to have these instances:

StateT s (ReaderT r m)               ReaderT r m                  r
WriterT w (ReaderT r m)              ReaderT r m                  r
MaybeT (ReaderT r m)                 ReaderT r m                  r
...

It turns out, though, that we don't need the HasReader class for any of these cases. We can just write the expression as a computation in m' and lift it up to m .

链接地址: http://www.djcxy.com/p/43524.html

上一篇: 错误无法匹配预期类型'Char'与实际类型'[Char]'

下一篇: 可以在Haskell实例声明中组合类型吗?