【问题标题】:Can I automatically implement classes?我可以自动实现类吗?
【发布时间】:2015-04-02 13:36:16
【问题描述】:

在 Scalaz 中,每个 Monad 实例自动成为 Applicative 的一个实例。

implicit val listInstance = new Monad[List] {
  def point[A](a: => A) = List(a)
  def bind[A, B](fa: List[A])(f: A => List[B]) = fa flatMap f
}

List(2) <*> List((x: Int) => x + 1) // Works!

另一个例子:Arrow 自动成为Profunctor

但是,在 Haskell 中,我必须一次又一次地为每个 Monad 提供一个 Applicative 实例。

是否可以避免这种重复性工作?

【问题讨论】:

  • 暂时没有,AFAIK。您必须添加instance Applicative M where pure=return; (&lt;*&gt;)=ap。我相信我看到了一些关于自动派生超类的讨论,即实现MonadFunctor 并隐式添加了Applicative,但它尚未实现(再次,AFAIK)。也许您可以编写一些 Template Haskell 来扫描当前的 monad 实例并自动生成应用程序。不过,我不确定这是否可行。

标签: haskell scalaz


【解决方案1】:

当有两个地方可以派生Applicative 实例时,问题就来了。例如,假设ma b 类型,其中Arrow a。然后从这个定义中也有一个明显的Applicative 实例。编译器应该使用哪一个?当然,结果应该是一样的,但是 Haskell 没有办法检查这一点。通过让我们写出实例,Haskell 至少迫使我们考虑定义的一致性。

如果你愿意,Control.Applicative 中有一个 WrappedMonad 类,它为所有明显的实例提供了一个 newtype 包装器,但一直使用 WrapMonadunwrapMonad 也没有那么吸引人。

【讨论】:

    【解决方案2】:

    目前不可能,但如果您更改现有库以支持此功能,则可以。打开 DefaultSignatures 会让你写

    class Applicative f where
        pure :: a -> f a
        (<*>) :: f (a -> b) -> f a -> f b
    
        default pure :: Monad f => a -> f a
        default (<*>) :: Monad f => f (a -> b) -> f a -> f b
        pure = return
        (<*>) = ap
    

    然后,一旦您实现了instance Monad M where {- ... -},一个简单的instance Applicative M(没有where 或方法定义)将继承这些默认实现。我不确定为什么没有这样做。

    【讨论】:

      猜你喜欢
      • 2016-01-12
      • 2020-07-27
      • 2014-01-19
      • 2010-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-04
      相关资源
      最近更新 更多