假设我有两个定义如下的类型类,它们的功能相同但名称不同:
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a
class PhantomMonad p where
pbind :: p a -> (a -> p b) -> p b
preturn :: a -> p a
有没有办法将这两个类绑定在一起,以便 PhantomMonad 的实例自动成为 Monad 的实例,或者必须显式编写每个类的实例?任何见解将不胜感激,谢谢!
好答案:不,您希望做的事情实际上并不可行。您可以编写一个看起来像您想要的那样的实例,在此过程中可能需要一些 GHC 扩展,但它不会按照您希望的方式工作。
不明智的回答:您可能可以使用可怕的类型级元编程来完成您想要的事情,但它可能会变得复杂。这真的不推荐,除非你绝对地由于某种原因需要这个工作。
正式来说,实例不能真正依赖于其他实例,因为 GHC 在做出决策时只查看“实例头”,而类约束位于“上下文”中。要在这里创建类似“类型类同义词”的内容,您必须编写类似于以下实例的内容Monad
for 所有可能的类型,这显然没有意义。您将与其他实例重叠Monad
,它有自己的问题。
最重要的是,我认为这样的实例无法满足实例解析的终止检查要求,因此您还需要UndecidableInstances
扩展名,这意味着能够编写将 GHC 的类型检查器发送到无限循环的实例。
如果你真的想深入那个兔子洞,请浏览奥列格·基谢廖夫的网站 http://okmij.org/ftp/一点点;他可以说是 Haskell 类型级元编程的守护神。
当然,这很有趣,但如果您只是想编写代码并让它工作,那么可能不值得这么痛苦。
Edit:好吧,事后看来,我在这里夸大了这个问题。就像是PhantomMonad
一次性工作正常,并且应该做你想做的事,考虑到Overlapping
- and UndecidableInstances
GHC 扩展。当你想做比问题中的事情复杂得多的事情时,复杂的事情就开始了。我真诚地感谢诺曼·拉姆齐(Norman Ramsey)给我打电话——我真的应该更清楚。
我还是不太明白推荐做这种事没有充分的理由,但它并不像我听起来那么糟糕。抱歉。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)