Hey All,

Suppose we have this generalized situation:

I have some class that does IO with user data, but we want to hide the full IO interface, so we do something like this:

class (Monad m) => Doohickey m where
  getCurrentTime  :: m Time
  olderRecords :: m [String]
  addRecord  :: String -> m ()

Suppose next that we want to run a monadic value of that type, with some context, inside another monad.

For example, we have some file on disk with user data.  We want the top level to open the file, and then run a monadic action with the above signature.   The username provides the context.  Give us a username, and we'll open a file, and then run a monadic value w/ the above signature on the file.  e.g.

class (Monad m) => TopLevel m where
  openFileAndRun :: (Doohickey n) => UserName -> n a -> m a

In this example, we could have a function that takes an input string s, goes through the old records, and if it sees that s is not present, then it will add it to the records.

Suppose then that we want to generalize the interface, so that it could apply equally to a local file, a db, the cloud, whatever.

That's why we need the Toplevel monad.  We want to separate "what we want to do with the user data" from "how we will store and modify the userdata".  Toplevel actions therefore needs to be able to execute Doohickey actions.

How would you guys do this?  I'm trying to write the signatures but ghc borks on "Ambiguous type variable in the constraints" error.  It appears to be caused by the usage of the Doohickey typeclass in the signature of Toplevel, when I actually try to write a monadic value of type Toplevel, that calls a monadic value of type Doohickey.

Much thanks for any help!

-Arthur