我可以显式地将类型类字典传递给函数吗?

时间:2016-06-30 18:44:04

标签: haskell ghc typeclass

假设我有一些类型类:

data Foo = Foo deriving (Show)

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

由于GHC通过字典传递实现了类型类(尽管使用了SPECIALIZE),它有效地将getFoo转换为类似下面的内容:

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

...它在调用getFoo的开头插入一个附加参数,该字符围绕着字典。

有时,我可能想要动态选择一个实例,因此自己传递一个字典可能是可取的。我可以通过创建一个将为我编写字典的实例来自己模拟。

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

instance MonadFoo DynamicMonadFoo where
  getFoo = join $ asks _getFoo

现在,给定一些带有MonadFoo约束的函数,我可以使用runFoo函数向它传递一个显式类型类字典:

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

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

这真的很酷,但似乎这样一个简单的任务,GHC可能会在没有所有样板的情况下暴露某种类型的库(理想情况下,这种方式可以更好地处理非monadic类型类)。鉴于GHC具有一些“反射式”功能,如Data.Typeable,这似乎不属于可能性范围,但我不确定它是否确实以某种形式存在。

任何现有的内置插件或其他库是否允许更自动地执行此操作?

1 个答案:

答案 0 :(得分:6)

在哈斯克尔学院有一篇关于此的文章:

Reflecting values to types and back

请参阅标题为Dynamically constructing type-class instancesBut what about manual dictionaries?

的结尾部分