سؤال

يمكنني استخدام = في سلم الفهم (كما هو محدد في القسم 6.19 من SLS) على النحو التالي:

خيار

لنفترض أن لدي بعض الوظائف String => Option[Int]:

scala> def intOpt(s: String) = try { Some(s.toInt) } catch { case _ => None }
intOpt: (s: String)Option[Int]

ثم يمكنني استخدامه بهذه الطريقة

scala> for {
   |     str <- Option("1")
   |     i <- intOpt(str)
   |     val j = i + 10    //Note use of = in generator
   |   }
   |   yield j
res18: Option[Int] = Some(11)

لقد كان فهمي أن هذا كان يعادل في الأساس ما يلي:

scala> Option("1") flatMap { str => intOpt(str) } map { i => i + 10 } map { j => j }
res19: Option[Int] = Some(11)

أي أن المولد المدمج كان وسيلة لحقن أ map في تسلسل flatMap المكالمات.حتى الان جيدة جدا.

إما.RightProjection

ما أريد فعلا أن أفعله: استخدم طريقة مشابهة للفهم مثل المثال السابق باستخدام Either مناد.

ومع ذلك، إذا استخدمناها في سلسلة مماثلة، ولكن هذه المرة باستخدام Either.RightProjection الموناد/العامل، لا يعمل:

scala> def intEither(s: String): Either[Throwable, Int] = 
  |      try { Right(s.toInt) } catch { case x => Left(x) }
intEither: (s: String)Either[Throwable,Int]

ثم استخدام:

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
                ^

تتعلق المشكلة بالوظيفة التي يتوقعها الإسقاط الأيمن كوسيطة لها flatMap الطريقة (أيانها تتوقع R => Either[L, R]).ولكن تعديل لعدم الاتصال right على المولد الثاني، فإنه لا يزال غير قادر على التجميع.

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)
                            ^

الارتباك الكبير

ولكن الآن أشعر بالارتباك المزدوج.ما يلي يعمل بشكل جيد:

scala> for {
 |       x <- Right[Throwable, String]("1").right
 |       y <- Right[Throwable, String](x).right //note the "right" here
 |     } yield y.toInt
res39: Either[Throwable,Int] = Right(1)

ولكن هذا لا:

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 }
                                                                                             ^

اعتقدت أن هذه كانت متكافئة

  • ما الذي يجري؟
  • كيف يمكنني تضمين = مولد في الفهم عبر Either?
هل كانت مفيدة؟

المحلول

حقيقة أنه لا يمكنك تضمين = في الفهم يتعلق هذه المسألة تقرير من جيسون زوغ.الحل هو الانحياز لليمين Either (أو قم بإنشاء نوع بيانات جديد متماثل له).

بسبب ارتباكك الشديد، قمت بتوسيع نطاق السكر بشكل غير صحيح.إزالة السكر من

for {
  b <- x(a)
  c <- y(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 => Right[Throwable, String](x).right map { y => y.toInt } }
res49: Either[Throwable,Int] = Right(1)

المزيد من المتعة حول إزالة السكر (المسألة `j = i + 10`)

for {
  b <- x(a)
  c <- y(b)
  x1 = f1(b)
  x2 = f2(b, x1)
  ...
  xn = fn(.....)
  d <- z(c, xn)
} yield w(d)

يتم إزالة السكر فيه

x(a) flatMap { b =>
  y(b) map { c =>
    x1 = ..
    ...
    xn = ..
    (c, x1, .., xn) 
  } flatMap { (_c1, _x1, .., _xn) =>
    z(_c1, _xn) map w }}

لذلك في حالتك، y(b) لديه نوع النتيجة Either الذي لا يملك map مُعرف.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top