2017-09-27 18 views
0

Je rencontre des problèmes avec cats/monads/understanding. S'il vous plaît envisager de suivre Snippet:Monade de Rien ne fonctionne pas chez les chats

import cats._ 
import cats.implicits._ 

final case class My[T]() 
implicit val monadMy: Monad[My] = new Monad[My] { ... } 

// this compiles 
def test11[A, B](m: My[A], f: A => B): My[B] = m.map(f) 
// this fails: value map is not a member of My[Nothing] 
def test12[B](m: My[Nothing], f: Nothing => B): My[B] = m.map(f) 

// this compiles 
def test21[A, B](m: My[A], f: A => My[B]): My[B] = m.flatMap(f) 
// this fails: type mismatch; 
// [error] found : A => My[Nothing] 
// [error] required: A => My[B] 
def test22[A](m: My[A], f: A => My[Nothing]): My[Nothing] = m.flatMap(f) 

Je me rends compte que test12 peut paraître étrange mais il permettrait for syntaxe:

for (...; nothing <- My[Nothing]()) yield nothing 

Mais l'échec montre test22 rend cats.monad inutilisable pour mon cas. La monade de Nothing viole-t-elle les lois de la monade?

S'il vous plaît aider, je voudrais être en mesure de flatMapM[Nothing].

Merci d'avance.

MISE À JOUR Cet extrait de code minimal compilerait si je faisais My covariant, mais malheureusement à l'origine j'utiliser cats.Free, que je n'ai pas accès.

MISE À JOUR Encore une solution consiste à utiliser la fonction polymorphique partout où j'utilise Nothing, à savoir utiliser test11 partout où je besoin test12, mais encore une fois, je voudrais comprendre pourquoi le comportement de M[Nothing] est différent de celui de tout autre type.

MISE À JOUR BTW, si je change Nothing par exemple. Int il va compiler. Donc, on dirait que c'est par conception. Mais pourquoi?

MISE À JOUR Autre solution de contournement: passez à scalaz.

MISE À JOUR Apparemment, le problème est purement lié à scala.

MISE À JOUR Solution de contournement: déclarez undefined type Bottom <: Nothing et utilisez-le à la place.

+3

esprit Je demande pourquoi vous avez besoin d'une monade de 'Nothing', qui est un type que vous ne pouvez pas créer? Qu'essayez-vous d'accomplir? –

+0

Par exemple, l'échec de la liste monad, qui, si elle se produisait, ferait passer tout à la liste vide, ce serait 'fail failure: List [Nothing] = Nil'. Bien sûr, je pourrais faire def def [T]: List [T] = Nil' et ça marcherait, mais ... –

+0

Que signifie l'échec de la liste monad? Pas sûr que je comprenne. –

Répondre

1

Essayez de faire My covariant dans T. Ensuite, le code compile.

final case class My[+T]() 

Avec invariant T il était

Information:27.09.17 15:55 - Compilation completed with 2 errors and 0 warnings in 2s 804ms 
/home/dmitin/Projects/myproject/src/main/scala/App.scala 

Information:(19, 59) toFunctorOps is not a valid implicit value for m.type => ?{def map: ?} because: 
type mismatch; 
found : m.type (with underlying type App.My[Nothing]) 
required: App.My[A] 
Note: Nothing <: A, but class My is invariant in type T. 
You may wish to define T as +T instead. (SLS 4.5) 
    def test12[B](m: My[Nothing], f: Nothing => B): My[B] = m.map(f) 

Error:(19, 61) value map is not a member of App.My[Nothing] 
    def test12[B](m: My[Nothing], f: Nothing => B): My[B] = m.map(f) 

Error:(26, 73) type mismatch; 
found : A => App.My[Nothing] 
required: A => App.My[B] 
    def test22[A](m: My[A], f: A => My[Nothing]): My[Nothing] = m.flatMap(f) 

Parfois, il est utile d'allumer scalacOptions += "-Xlog-implicits"

+1

Cela aiderait, mais je ne suis pas capable de le rendre covariant, puisque à l'origine j'utilise 'cats.Free' qui n'est pas covariant mais son deuxième argument. Je vais mettre à jour ma question. –