2015-04-02 94 views
9

在斯卡拉兹每个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的实例。

是否可以避免这个重复的工作?

+0

目前还没有,AFAIK。你必须添加'实例Applicative M,其中pure = return; (<*>)= ap'。我相信我看到了一些关于autoderiving超类的讨论,即实现'Monad'和'Functor'并隐式添加'Applicative',但尚未实现(再次AFAIK)。也许你可以编写一些模板Haskell来扫描当前monad实例并自动生成应用程序。不过,我不确定这是可能的。 – chi 2015-04-02 14:31:31

回答

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或方法的定义)将继承这些默认的实现。我不知道为什么这没有完成。

3

问题出现时,有两个地方可以派生出Applicative实例。例如,假设m是类型a b,其中Arrow a。那么这个定义中还有一个明显的Applicative实例。编译器应该使用哪一个?当然,它应该是相同的,但Haskell无法检查这一点。通过让我们写出实例,Haskell至少迫使我们考虑定义的一致性。

如果你想,有个WrappedMonadControl.Applicative,它提供了所有明显的情况下,用newtype包装,但使用WrapMonadunwrapMonad所有的时间是不是有吸引力的要么。

相关问题