2015-04-02 17 views
9

In Scalaz ogni istanza Monad è automaticamente un'istanza di Applicative.Posso implementare automaticamente le classi?

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! 

Un altro esempio: Arrow è automaticamente un Profunctor.

Tuttavia, in Haskell devo fornire un'istanza di Applicative per ogni Monad ancora e ancora.

È possibile evitare questo lavoro ripetitivo?

+0

Non al momento, AFAIK. Devi aggiungere istanza applicativa M dove pure = return; (<*>) = ap'. Credo di aver visto alcune discussioni sulle superclassi di conversione automatica, cioè implementare 'Monad' e' Functor' e avere 'Applicative' implicitamente aggiunto, ma non è stato implementato (di nuovo, AFAIK). Forse puoi scrivere alcuni Template Haskell per scansionare le istanze monade correnti e generare applicazioni auto-generanti. Non sono sicuro che sia possibile, comunque. – chi

risposta

2

Non è attualmente possibile, anche se lo sarebbe se la libreria esistente fosse stata modificata per supportarla. Girando DefaultSignatures sul avrebbe lasciato che si scrive

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 

Poi una volta che aveva attuato instance Monad M where {- ... -}, un semplice instance Applicative M (senza where o metodo definizioni) avrebbe ereditato queste implementazioni di default. Non sono sicuro del motivo per cui non è stato fatto.

3

Il problema si presenta quando ci sono due posizioni da cui derivare l'istanza Applicative. Ad esempio, supponiamo che m sia il tipo a b dove Arrow a. Quindi c'è un'ovvia istanza di Applicative anche da questa definizione. Quale dovrebbe essere il compilatore? Ovviamente dovrebbe funzionare lo stesso, ma Haskell non ha modo di verificarlo. Facendoci scrivere le istanze, Haskell ci costringe almeno a riflettere sulla coerenza delle nostre definizioni.

Se si desidera, c'è la classe WrappedMonad in Control.Applicative, che fornisce tutte le istanze ovvie con un newtype involucro, ma utilizzando WrapMonad e unwrapMonad tutto il tempo non è così attraente sia.

Problemi correlati