views:

86

answers:

1

Is it possible to use type synonyms as arguments of monad transformers' type constructor? In particular, if there is an unary type synonym for an applied monad transformer, could it be used as a type of the underlying monad in another monad transformer?

From what I see type synonyms are not accepted as first-class type constructors, see example and error messages below:

-- Using type synonym of a monad transformer in another monad transformer.

import Control.Monad.Reader

-- inner transformer
type A a = ReaderT Int IO a

-- type B a = ReaderT String A a
{- Error:
readert2.hs:8:0:
    Type synonym `A' should have 1 argument, but has been given 0
    In the type synonym declaration for `B'
-}

-- type B a = ReaderT String (A a) a
{- Error:
readert2.hs:15:27:
    Kind mis-match
    The second argument of `ReaderT' should have kind `* -> *',
    but `A a' has kind `*'
    In the type `ReaderT String (A a) a'
    In the type synonym declaration for `B'
-}

type B a = ReaderT String (ReaderT Int IO) a
{- OK -}

main = do
  r <- flip runReaderT 39 $ do
          n <- ask :: A Int
          s <- flip runReaderT "foo" $ (ask :: B String)
          return $ n + length s
  print r

Is there a way to avoid expanding the type synonym A in the definition of B a?

+7  A: 

Type synonyms cannot be partially applied. In this specific case, you can write

type A = ReaderT Int IO
type B a = ReaderT String A a

[or even better type B = ReaderT String A to use B in another monad transformer]

It's general, that transformation is impossible without using newtype/data, for example:

type A a = Reader a Int

cannot be equivalently written as type A = .... In some sense, this feature would be equivalent to type-level lambda \a -> Reader a Int.

sdcvvc