gfxmonk
gfxmonk

Reputation: 8736

How can I give this sub-function an explicit type?

I have the following haskell code to expand environment variables in strings (parsing code omitted):

import Control.Monad (liftM)

data Token = Literal String | EnvReference String deriving Show

expandTokens :: (Monad m) => (String -> m (Maybe String)) -> [Token] -> m String
expandTokens getEnv toks = liftM concat (mapM toString toks) where
    toString (Literal s) = return s
    toString (EnvReference v) = liftM (maybe "" id) (getEnv v)

(it's intended to be used with an IO implementation of getEnv, but I figured it would be nicer for testing if it could be used with any monad)

When I was writing it, I tried to give the nested toString function an explicit type of:

toString :: Monad m => Token -> m String

But ghc says:

Sample.hs:8:58:
    Could not deduce (m ~ m1)
    from the context (Monad m)
      bound by the type signature for
                 expandTokens :: Monad m =>
                                 (String -> m (Maybe String)) -> [Token] -> m String
( ... )

I get that the "Monad m" in the expandTokens must necessarily be the exact same m as in the type of toString (since it references the getenv of the containing function), but I can't figure out how to write an explicit type for toString which respects that - I don't think there's any way to refer to anything in a different type declaration, can it even be done?

Upvotes: 4

Views: 496

Answers (1)

phipsgabler
phipsgabler

Reputation: 20950

I think you're looking for ScopedTypeVariables. I've never used that, but it looks right.

Upvotes: 4

Related Questions