2015-04-02 4 views
9

В 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 я должен предоставить экземпляр Applicative за каждые Monad снова и снова.

Можно ли избежать этой повторяющейся работы?

+0

В настоящее время, AFAIK. Вы должны добавить 'instance Applicative M, где pure = return; (<*>) = ap'. Я считаю, что я видел некоторую дискуссию об автокодирующих суперклассах, т. Е. Реализовал «Monad» и «Functor» и неявно добавил «Applicative», но он не был реализован (опять же, AFAIK). Возможно, вы можете написать шаблон Template Haskell для сканирования текущих экземпляров монады и автоматических аппликаций. Я не уверен, что это возможно. – chi

ответ

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 нет возможности проверить это. Заставляя нас выписывать примеры, Хаскелл по крайней мере заставляет нас задуматься о последовательности наших определений.

Если вы хотите, есть WrappedMonad класс Control.Applicative, который обеспечивает все очевидные случаи с newtype обертки, но с использование WrapMonad и unwrapMonad всего времени не то, что привлекательное либо.

Смежные вопросы