7
votes

Let’s say I have some typeclass:

data Foo = Foo deriving (Show)

class Monad m => MonadFoo m where
  getFoo :: m Foo

Since GHC implements typeclasses via dictionary passing (uses of SPECIALIZE notwithstanding), it effectively transforms getFoo into something like the following under the hood:

data MonadFooDict m = MonadFooDict { getFoo :: m Foo }

...and it inserts an additional argument at the beginning of calls to getFoo that threads the dictionary around.

Sometimes, I might want to pick an instance dynamically, so passing a dictionary myself might be desirable. I can simulate this myself by creating an instance that will thread the dictionary around for me.

newtype DynamicMonadFoo a = DynamicMonadFoo
    { runFoo :: MonadFooDict DynamicMonadFoo -> a }
  deriving ( Functor, Applicative, Monad
           , MonadReader (MonadFooDict DynamicMonadFoo) )

instance MonadFoo DynamicMonadFoo where
  getFoo = join $ asks _getFoo

Now, given some function with a MonadFoo constraint, I can use the runFoo function to pass it an explicit typeclass dictionary:

showCurrentFoo :: MonadFoo m => m String
showCurrentFoo = do
  foo <- getFoo
  return ("current foo: " ++ show foo)

ghci> runFoo showCurrentFoo MonadFooDict { _getFoo = return Foo }
"current foo: Foo"

This is really cool, but it seems like such a simple task that GHC might expose some sort of library to do this without all the boilerplate (and ideally in a way that would work more nicely with non-monadic typeclasses). Given that GHC has some “reflection-esque” capabilities like Data.Typeable, this doesn’t seem outside the realm of possibility, but I’m not sure if it actually exists in some form.

Do any existing built-ins or other libraries allow doing this more automatically?

1
You can with the new explicit type application extension, more details herepdexter
@pdexter Unless I’m missing something, that seems unrelated to me—it seems mostly syntactic and about working with values at the type level exclusively, while this question is about passing a dynamic runtime value as a typeclass dictionary. However, I could be misinterpreting the link, in which case an answer demonstrating it would be much appreciated!Alexis King

1 Answers

6
votes

There is an article on this at the School of Haskell:

Reflecting values to types and back

See the section towards the end entitled Dynamically constructing type-class instances and But what about manual dictionaries?