Monad of Nothing在猫

时间:2017-09-27 11:15:41

标签: scala monads scalaz scala-cats

我遇到cats / monads /理解问题。 请考虑以下代码段:

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)

我意识到test12可能看起来很奇怪,但它会允许for语法:

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

test22中显示的失败导致cats.monad无效。 Nothing的monad是否违反了monad法律?

请提供帮助,我希望能够flatMap M[Nothing]

提前致谢。

更新如果我提出My协变,这个最小的代码段就会编译,但遗憾的是我最初使用的是cats.Free,我无权访问。

更新另一个解决方法是在我使用Nothing的任何地方使用多态函数,即在我需要test11的任何地方使用test12,但我想再次了解为什么M[Nothing]的行为与任何其他类型的行为不同。

更新 BTW,如果我将Nothing更改为例如Int它会编译。所以,看起来这是设计的。但为什么呢?

更新另一种解决方法:切换到scalaz

更新看起来问题纯粹与scala有关。

更新解决方法:声明未定义type Bottom <: Nothing并改为使用它。

1 个答案:

答案 0 :(得分:1)

尝试在My中设置T协变。然后代码编译。

final case class My[+T]()

使用不变T,它是

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)

有时打开scalacOptions += "-Xlog-implicits"

非常有用