0

I am having issues with cats/monads/understanding. Please consider following snippet:

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)

I realize that test12 may look strange however it would allow for syntax:

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

But failure shown in test22 makes cats.monad unusable for my case. Is monad of Nothing violates monad laws?

Please assist, I would want to be able to flatMap M[Nothing].

Thanks in advance.

UPDATE This minimal code snippet would compile if I made My covariant, but unfortunately originally I use cats.Free, which I don't have access to.

UPDATE One more workaround is to use polymorphic function everywhere I use Nothing, i.e. use test11 everywhere I need test12, but again, I would like to understand why behavior for M[Nothing] is different than for any other type.

UPDATE BTW, if I change Nothing to e.g. Int it will compile. So, looks like this is by design. But why?

UPDATE Another workaround: switch to scalaz.

UPDATE Looks like issue is related purely to scala.

UPDATE Workaround: declare undefined type Bottom <: Nothing and use it instead.

Dmytro Starosud
  • 397
  • 1
  • 15
  • 3
    Mind I ask why you need a monad of `Nothing`, which is a type you can't create? What are you trying to achieve? – Yuval Itzchakov Sep 27 '17 at 12:02
  • For example failure for list monad, which if occurred would turn everything to empty list, that would be `val failure: List[Nothing] = Nil`. Off course I could do `def failure[T]: List[T] = Nil` and it would work, but... – Dmytro Starosud Sep 27 '17 at 12:15
  • What does failure of list monad mean? Not sure I understand. – Yuval Itzchakov Sep 27 '17 at 12:17
  • This is kind of agreement that empty list means failure In the same way `Either`'s `Left[Something]` is failure, and `Option`'s `None` is failure. – Dmytro Starosud Sep 27 '17 at 12:23
  • Since you can not create an Instance of nothing you can not create a type class instance for it, Using option is more reasonable for your use case anyway, a List[Nothing] is meaningless while List[Option] is. – raam86 Sep 27 '17 at 13:34
  • @DmytroStarosud "UPDATE BTW, if I change Nothing to e.g. Int it will compile. So, looks like this is by design. But why?" Sometimes implicits start to work weird with Nothing or Any. – Dmytro Mitin Sep 27 '17 at 14:27
  • So, bug? I will probably report it... – Dmytro Starosud Sep 27 '17 at 14:30
  • Possible [duplicate](https://stackoverflow.com/questions/24887098/scala-type-parameter-inference-fails-for-nothing). – Dmytro Starosud Sep 27 '17 at 15:20

1 Answers1

1

Try to make My covariant in T. Then the code compiles.

final case class My[+T]()

With invariant T it was

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)

Sometimes it's useful to switch on scalacOptions += "-Xlog-implicits"

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
  • 1
    That would help, but I am not able to make it covariant, since originally I use `cats.Free` which is not covariant but its second argument. I will update my question. – Dmytro Starosud Sep 27 '17 at 13:22