Can I automatically implement classes?
Asked Answered
B

2

9

In Scalaz every Monad instance is automatically an instance of 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!

Another example: Arrow is automatically a Profunctor.

However, in Haskell I must provide an instance of Applicative for every Monad again and again.

Is it possible to avoid this repetitive job?

Branchia answered 2/4, 2015 at 13:36 Comment(1)
Not at the moment, AFAIK. You have to add instance Applicative M where pure=return; (<*>)=ap. I believe I saw some discussion about autoderiving superclasses, i.e. implement Monad and Functor and have Applicative implicitly added, but it has not been implemented (again, AFAIK). Perhaps you can write some Template Haskell to scan the current monad instances and autogenerate applicatives. I'm not sure this is possible, though.Compensatory
R
2

It isn't currently possible, though it would be if you changed the existing library to support this. Turning DefaultSignatures on would let you write

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

Then once you had implemented instance Monad M where {- ... -}, a simple instance Applicative M (with no where or method definitions) would inherit these default implementations. I'm not sure why this wasn't done.

Refutation answered 3/4, 2015 at 0:9 Comment(0)
A
3

The problem comes when there are two places from which to derive the Applicative instance. For instance, suppose m is the type a b where Arrow a. Then there's an obvious instance of Applicative from this definition as well. Which one should the compiler use? It should work out the same, of course, but Haskell has no way to check this. By making us write out the instances, Haskell at least forces us to think about the consistency of our definitions.

If you want, there's the WrappedMonad class in Control.Applicative, which provides all the obvious instances with a newtype wrapper, but using WrapMonad and unwrapMonad all the time isn't that attractive either.

Autecology answered 2/4, 2015 at 14:43 Comment(0)
R
2

It isn't currently possible, though it would be if you changed the existing library to support this. Turning DefaultSignatures on would let you write

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

Then once you had implemented instance Monad M where {- ... -}, a simple instance Applicative M (with no where or method definitions) would inherit these default implementations. I'm not sure why this wasn't done.

Refutation answered 3/4, 2015 at 0:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.