磁铁图案和匿名功能:缺少参数类型错误

Magnet pattern and anonmyous functions: Missing parameter type error

我正在使用磁铁模式根据是否存在某些隐式参数来调用正确的重载方法 (flatMap)。

https://scastie.scala-lang.org/pYQG0Q6TTWuvbjatD7SIxw

import scala.language.implicitConversions

object Tester {
  final case class Foo[A](value: A) {
    def flatMap[B](cat: Cat[A, B]): Foo[B] = {
      println("cat")
      cat.f(value)
    }

    def flatMap[B](monkey: Monkey[A, B]): Foo[B] = {
      println("monkey")
      monkey.f(value)
    }

    def map[B](f: A => B): Foo[B] = {
      Foo(f(value))
    }
  }

  case class Banana()
  class Monkey[A, B](val f: A => Foo[B])

  object Monkey {
    implicit def funcToMonkey[A, B](f: A => Foo[B])(implicit i: Banana): Monkey[A, B] = new Monkey(f)
  }
  case class Catnip()
  class Cat[A, B](val f: A => Foo[B])

  object Cat {
    implicit def funcToCat[A, B](f: A => Foo[B])(implicit i: Catnip): Cat[A, B] = new Cat(f)
  }

}

object Main {
  import Tester._
  def main(args: Array[String]) = {
    for {
      _ <- Foo(1)
      _ <- Foo("asdf")
    } yield ()
  }
}

但是我收到错误 missing parameter type for expanded function。 如果我将其脱糖以直接进行 flatMap 调用,我会收到类似的错误:

Foo(1).flatMap(_ => Foo("asdf").map(_ => ()))

missing parameter type

我可以通过显式指定 flatMap 参数的类型(即 .flatMap((_: Int) => ...))来解决问题,但我想避免这种情况。即使我确实使用了参数,Scala 仍然要求我指定类型

有没有办法编译 for comprehension 代码?

我认为这行不通。为避免必须为 lambda 提供参数类型,预期类型(此处为 flatMap 参数类型)必须是函数类型或 SAM 类型,而不仅仅是某种从函数类型隐式转换的类型,例如CatMonkey 是。

在 2.13 之前,您还会 运行 遇到一个单独的问题,因为不允许重载该方法,但修复也没有涵盖您的情况:

To avoid breaking existing code, we only provide an expected type (for each argument position) when:

  • there is at least one FunctionN type expected by one of the overloads: in this case, the expected type is a FunctionN[Ti, ?], where Ti are the argument types (they must all be =:=), and the expected result type is elided using a wildcard. This does not exclude any overloads that expect a SAM, because they conform to a function type through SAM conversion

  • OR: all overloads expect a SAM type of the same class, but with potentially varying result types (argument types must be =:=)

这些都不适合您(CatMonkey 不是 SAM 类型,即使它们有效也不会起作用)。我试图让 flatMap 直接使用隐含函数

import scala.language.implicitConversions
object Tester {
  final case class Foo[A](value: A) {
    def flatMap[B](f: A => Foo[B])(implicit i: Catnip): Foo[B] = {
      val cat: Cat[A, B] = f
      println("cat")
      cat.f(value)
    }

    def flatMap[B](f: A => Foo[B])(implicit i: Banana): Foo[B] = {
      val monkey: Monkey[A, B] = f
      println("monkey")
      monkey.f(value)
    }

    def map[B](f: A => B): Foo[B] = {
      Foo(f(value))
    }
  }

  case class Banana()
  class Monkey[A, B](val f: A => Foo[B])

  object Monkey {
    implicit def funcToMonkey[A, B](f: A => Foo[B])(implicit i: Banana): Monkey[A, B] = new Monkey(f)
  }
  case class Catnip()
  class Cat[A, B](val f: A => Foo[B])

  object Cat {
    implicit def funcToCat[A, B](f: A => Foo[B])(implicit i: Catnip): Cat[A, B] = new Cat(f)
  }

}

object Main {
  import Tester._
  implicit val cn = Catnip()
  def main(args: Array[String]) = {
    for {
      _ <- Foo(1)
      _ <- Foo("asdf")
    } yield ()
  }
}

但这只是给出了不同的错误:

ambiguous reference to overloaded definition,
both method flatMap in class Foo of type [B](f: Int => Tester.Foo[B])(implicit i: Tester.Banana)Tester.Foo[B]
and  method flatMap in class Foo of type [B](f: Int => Tester.Foo[B])(implicit i: Tester.Catnip)Tester.Foo[B]
match argument types (Int => Tester.Foo[Unit])