本文介绍了正确的投影混淆(理解脱糖)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我可以在scala for-comprehension中使用 = (如 6.19 的SLS )如下所示: h2> 假设我有一些函数 String =>选项[Int] : scala> def intOpt(s:String)= try {Some(s.toInt)} catch {case _ =>无} intOpt:(s:String)选项[Int] 然后我可以使用它因此 scala>为{ | str< - Option(1) |我< - intOpt(str) | val j = i + 10 //注意在生成器 |中使用= } |产量j res18:Option [Int] =一些(11) 这是我的理解这基本上相当于: scala>选项(1)flatMap {str => intOpt(str)} map {i => i + 10} map {j => j} res19:Option [Int] =一些(11) 也就是说,嵌入式生成器是一种将 map 注入到 flatMap 调用序列中的方法。到目前为止这么好。 或者.RightProjection 我真正想做的事:使用与前面使用任一 monad 的示例类似的理解。 Either.RightProjection monad / functor,它不起作用: scala> def intEither(s:String):或者[Throwable,Int] = |尝试{Right(s.toInt)} catch {case x => Left(x)} intEither:(s:String)[Throwable,Int] 然后使用: scala>为{ | str< - Option(1)。toRight(new Throwable())right |我< - intEither(str).right //注意右投影使用 | val j = i + 10 | } | (java.lang.Throwable,(Int,Int)] i< - intEither(str);返回值为j < console>:17:error:value map不是Product的一个成员, ).right ^ 这个问题与这个函数有关,投影期望作为其 flatMap 方法的一个参数(即它期望一个 R => [L,R] )。但修改为不在第二个生成器上调用 right ,它仍然不会编译。 阶>为{ | str< - Option(1)。toRight(new Throwable())right |我< - intEither(str)//否rightprojection | val j = i + 10 | } | yield j < console>:17:error:value map不是Either [Throwable,Int] i ^ 的成员。 code> 超级混乱 但现在我倍感困惑。下面的例子很好: scala>为{ | x< - 右[Throwable,String](1)。右 | y< - 右[Throwable,String](x).right //注意这里的right | } yield y.toInt res39:或者[Throwable,Int] = Right(1) 但是这不是: scala> Right [Throwable,String](1)。right flatMap {x =>右[Throwable,String](x).right} map {y => y.toInt} < console>:14:error:type mismatch; found:Either.RightProjection [Throwable,String] required:[?,?] Right [Throwable,String](1)。right flatMap {x =>右[Throwable,String](x).right} map {y => y.toInt} ^ 我认为这些是相同的 发生了什么事情? 如何嵌入 = 在> ? 解析方案 div> 不能将 = 嵌入到for-comprehension中的事实与这个问题由Jason Zaugg报道;解决的办法是右偏或者(或者创建一个与它同构的新数据类型)。 巨大的困惑,你不正确地扩大了糖。 (b c $ b )} yield z(c) 是 x(a)flatMap {b => y(b)map {c => z(c)}} 而不是 x(a)flatMap {b => y(b)} map {c => z(c)} 因此您应该这样做: scala> Right [Throwable,String](1)。right flatMap {x =>右[Throwable,String](x).right map {y => y.toInt}} res49:[Throwable,Int] = Right(1) 关于desugaring(`j = i + 10`问题)的更多乐趣 对于{b c x1 = f1(b) x2 = f2(b,x1) ... xn = fn (.....)d }得到w(d) 被解析成 x(a)flatMap {b => y(b)map {c => x1 = .. ... xn = .. (c,x1,..,xn)} flatMap {(_c1,_x1,。 。,_xn)=> z(_c1,_xn)map w}} $ c> y(b)的结果类型为或者不包含 map 定义。 I can use an = in a scala for-comprehension (as specified in section 6.19 of the SLS) as follows:OptionSuppose I have some function String => Option[Int]:scala> def intOpt(s: String) = try { Some(s.toInt) } catch { case _ => None }intOpt: (s: String)Option[Int]Then I can use it thusscala> for { | str <- Option("1") | i <- intOpt(str) | val j = i + 10 //Note use of = in generator | } | yield jres18: Option[Int] = Some(11)It was my understanding that this was essentially equivalent to:scala> Option("1") flatMap { str => intOpt(str) } map { i => i + 10 } map { j => j }res19: Option[Int] = Some(11)That is, the embedded generator was a way of injecting a map into a sequence of flatMap calls. So far so good.Either.RightProjectionWhat I actually want to do: use a similar for-comprehension as the previous example using the Either monad.However, if we use it in a similar chain, but this time using the Either.RightProjection monad/functor, it doesn't work:scala> def intEither(s: String): Either[Throwable, Int] = | try { Right(s.toInt) } catch { case x => Left(x) }intEither: (s: String)Either[Throwable,Int]Then use:scala> for { | str <- Option("1").toRight(new Throwable()).right | i <- intEither(str).right //note the "right" projection is used | val j = i + 10 | } | yield j<console>:17: error: value map is not a member of Product with Serializable with Either[java.lang.Throwable,(Int, Int)] i <- intEither(str).right ^The issue has something to do with the function that a right-projection expects as an argument to its flatMap method (i.e. it expects an R => Either[L, R]). But modifying to not call right on the second generator, it still won't compile.scala> for { | str <- Option("1").toRight(new Throwable()).right | i <- intEither(str) // no "right" projection | val j = i + 10 | } | yield j<console>:17: error: value map is not a member of Either[Throwable,Int] i <- intEither(str) ^Mega-ConfusionBut now I get doubly confused. The following works just fine:scala> for { | x <- Right[Throwable, String]("1").right | y <- Right[Throwable, String](x).right //note the "right" here | } yield y.toIntres39: Either[Throwable,Int] = Right(1)But this does not:scala> Right[Throwable, String]("1").right flatMap { x => Right[Throwable, String](x).right } map { y => y.toInt }<console>:14: error: type mismatch; found : Either.RightProjection[Throwable,String] required: Either[?,?] Right[Throwable, String]("1").right flatMap { x => Right[Throwable, String](x).right } map { y => y.toInt } ^I thought these were equivalentWhat is going on?How can I embed an = generator in a for comprehension across an Either? 解决方案 The fact that you cannot embed the = in the for-comprehension is related to this issue reported by Jason Zaugg; the solution is to Right-bias Either (or create a new data type isomorphic to it).For your mega-confusion, you expanded the for sugar incorrectly. The desugaring offor { b <- x(a) c <- y(b)} yield z(c)isx(a) flatMap { b => y(b) map { c => z(c) }} and notx(a) flatMap { b => y(b)} map { c => z(c) }Hence you should have done this:scala> Right[Throwable, String]("1").right flatMap { x => Right[Throwable, String](x).right map { y => y.toInt } }res49: Either[Throwable,Int] = Right(1)More fun about desugaring (the `j = i + 10` issue)for { b <- x(a) c <- y(b) x1 = f1(b) x2 = f2(b, x1) ... xn = fn(.....) d <- z(c, xn)} yield w(d)is desugared intox(a) flatMap { b => y(b) map { c => x1 = .. ... xn = .. (c, x1, .., xn) } flatMap { (_c1, _x1, .., _xn) => z(_c1, _xn) map w }}So in your case, y(b) has result type Either which doesn't have map defined. 这篇关于正确的投影混淆(理解脱糖)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 10-29 16:44