假设我有一些类型类:
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
,这似乎不属于可能性范围,但我不确定它是否确实以某种形式存在。
任何现有的内置插件或其他库是否允许更自动地执行此操作?
答案 0 :(得分:6)
在哈斯克尔学院有一篇关于此的文章:
Reflecting values to types and back
请参阅标题为Dynamically constructing type-class instances和But what about manual dictionaries?
的结尾部分