【问题标题】:Scala for-comprehension with tuple decompositionScala 用于理解元组分解
【发布时间】:2015-12-15 13:30:27
【问题描述】:
for {
  a <- Some(1)
  b <- Some(2)
} yield (a, b)

返回Some((1, 2))

for {
  a <- Right(1).right
  b <- Left(2).left
} yield (a, b)

返回Left((1, 2))


现在我想在 for 理解中分解元组。

for {
  (a, b) <- Some((1, 2))
  (c, d) <- Some((3, 4))
} yield (a, b, c, d)

返回Some((1, 2, 3, 4))

for {
  (a, b) <- Right((1, 2)).right
  (c, d) <- Left((3, 4)).left
} yield (a, b, c, d)

编译失败:

error: constructor cannot be instantiated to expected type;
found   : (T1, T2)
required: scala.util.Either[Nothing,(Int, Int)]
                   (a, b) <- Right((1, 2)).right

error: constructor cannot be instantiated to expected type;
found   : (T1, T2)
required: scala.util.Either[(Int, Int),Nothing]

为什么最后一个例子不起作用?有什么区别?

【问题讨论】:

  • 报告了此问题的bug

标签: scala for-comprehension


【解决方案1】:

这是一个错误:

SI-5589: For-comprehension on Either.RightProjection with Tuple2 extractor in generator fails to compile

withFilter() 被调用(一些文档引用filter(),但在 2.8 中已更改),这与类型推断相混淆。

withFilter() 用于for(a &lt;- b if c) 之类的东西,但根据6.19,在这种情况下不应该使用它。

后一个错误在SI-1336: spec requires type checking of for-comprehension to consider refutability 中被捕获,它已经开放了七年(2008 年)。

也许未来的某些人会找到解决办法。


why does filter have to be defined for pattern matching in a for loop in scala?

【讨论】:

    【解决方案2】:

    因为 (Any, Any) 的生成器 why does filter have to be defined for pattern matching in a for loop in scala?) 中,导致:

    Right((1, 2)).right.filter { case (a, b) => true; case _ => false }.flatMap({
      case(a, b) => Left((3, 4)).left.filter { case (c, d) => true; case _ => false }.map({case (c, d) =>
        (a, b, c, d)
      })
    })
    

    过滤器是发生编译错误的地方,因为 Right 的过滤器方法看起来像这样(Left 类似):

    def filter[X](p: B => Boolean): Option[Either[X, B]] = e match {
      case Left(_) => None
      case Right(b) => if(p(b)) Some(Right(b)) else None
    }
    

    这意味着编译器正在尝试执行以下操作:

    (T1, T2) match {
      case Left(_) => None
      case Right(b) => if(p(b)) Some(Right(b)) else None
    }
    

    失败,因为 (T1, T2) 不能转换为 Either[A, B](Right 扩展的内容),其中 A 是 Nothing 而 B 是 (Int, Int)。

    您可以使用以下方法获得接近此的内容:

    for {
      a <- Right((1, 2)).right
      b <- Left((3, 4)).left
    } yield (a, b) match {
      case ((c, d), (e, f)) => (c, d, e, f)
      case _ => 
    }
    

    【讨论】:

      【解决方案3】:

      这可能是 for 表达式的限制。翻译

      for {
        (a, b) <- Some((1, 2))
        (c, d) <- Some((3, 4))
      } yield (a, b, c, d)
      

      进入

      Some((1, 2)).flatMap({case(a, b) =>
        Some((3, 4)).map({case (c, d) =>
          (a, b, c, d)
        })
      })
      

      双向工作。使用 Either 表达式,只有 map/flatMap 版本有效。

      for {
        (a, b) <- Right((1, 2)).right
        (c, d) <- Left((3, 4)).left
      } yield (a, b, c, d)
      
      
      Right((1, 2)).right.flatMap({
        case(a, b) => Left((3, 4)).left.map({case (c, d) =>
          (a, b, c, d)
        })
      })
      

      我不推荐使用Either,而是使用\/ 类型 斯卡拉兹http://eed3si9n.com/learning-scalaz/Either.html Either 不是 左倾或右倾,这是一个问题,因为它没有指定 错误或值在哪里。

      【讨论】:

      • Either 可能不是右倾或左倾,但LeftProjectionRightProjection 肯定是!
      • @PaulDraper 是的,但是每次你想使用它时都必须指定.right.left。而且我更喜欢没有噪音的代码。
      猜你喜欢
      • 2014-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-06
      • 2011-11-16
      相关资源
      最近更新 更多