Ошибка типа Scala с Try[Int]

у меня проблема с типами, которые я не понимаю. В приведенном ниже коде у меня есть два метода half1 и half2 которые точно такие же, кроме half1тип возврата указан явно. Но когда я использую два метода в foldLeft half вызывает ошибку компилятора. Вот код. Линия, которая устанавливает val c есть проблема.

package org.bodhi.reactive.`try`

import scala.util.{Try, Success, Failure}

object Hello {
   def main(args: Array[String]): Unit = {

    val list = List(1,2,3)

    Try(1024).flatMap(half1)
    Try(1024).flatMap(half2)

    half1(1024).flatMap(half1)
    half2(1024).flatMap(half2)

    val a = list.foldLeft(Try(1024))((accum, n) => accum.flatMap(half1))
    val b = list.foldLeft(half1(1024))((accum, n) => accum.flatMap(half1))
    val c = list.foldLeft(half2(1024))((accum, n) => accum.flatMap(half2)) // Compiler error

  }

  def half1(n: Int): Try[Int] =  
    if (n % 2 == 0) Success(n / 2)
    else Failure(new Exception(s"WRONG $n"))

  def half2(n: Int) =
    if (n % 2 == 0) Success(n / 2)
    else Failure(new Exception(s"WRONG $n"))
}

ошибка, которую я получаю:

[error] /home/chris/projects/reactive/example/src/main/scala/org/bodhi/reactive/try/Hello.scala:18: type mismatch;
[error]  found   : scala.util.Try[Int]
[error]  required: Product with Serializable with scala.util.Try[Int]
[error]     val c = list.foldLeft(half2(1024))((accum, n) => accum.flatMap(half2))

мой вопрос: почему half1 comile в foldLeft, но half2 тут нет? Я использую scala 2.11.5

1 ответов


и Success и Failure расширения Try[T] with Product with Serializable, (Product with Serializable потому что они являются классами case). Поэтому, когда вы оставляете тип возврата выключенным half2, возвращаемый тип выводится как Try[T] with Product with Serializable.

обычно это не имеет значения,flatMap(half2) вернет Try[T]

scala> Try(1024).flatMap(half2)
res2: scala.util.Try[Int] = Success(512)

но foldLeft - это другая история. Проблема в том, когда вы проходите half(2) в качестве первого аргумента. Давайте посмотрим на подпись foldLeft:

def foldLeft[B](z: B)(op: (A, B) => B): B

B выводится из аргумента z, что означает

B = Try[T] with Product with Serializable

что это значит op ожидается, что типа:

(A, Try[T] with Product with Serializable) => Try[T] with Product with Serializable

но вместо этого он (A, Try[T]) => Try[T], и, таким образом, вы получаете несоответствие типов. Использование вывода типа может быть приятным, но большую часть времени явно вводить возвращаемые типы сэкономит вам много головных болей.