For understanding fails when using an intermediate variable

version of scastie

With this infrastructure:

trait Pat[A]
object Pat {
  def apply[A](elems: A*): Pat[A] = ???
}

implicit class PatOps[A](p: Pat[A]) {
  def ++ (that: Pat[A]): Pat[A] = ???

  def bubble: Pat[Pat[A]] = ???

  def grouped(size: Pat[Int]): Pat[Pat[A]] = ???
}

implicit class PatPatOps[A](p: Pat[Pat[A]]) {
  def map[B](f: Pat[A] => Pat[B]): Pat[Pat[B]] = ???

  def flatMap[B](f: Pat[A] => Pat[B]): Pat[B] = ???

  def flatten: Pat[A] = ???
}

You can write the following for understanding:

trait Test1 {
  val lPat = Pat(1, 2, 3)
  val xs = for {
    len     <- lPat.bubble
    cantus  <- Pat(4, 40, 3).grouped(len)
  } yield {
    cantus ++ Pat(-1)
  }
  xs.flatten
}

But this one, using an intermediate variable, fails:

trait Test2 {
  val lPat = Pat(1, 2, 3)
  val xs = for {
    len     <- lPat.bubble  // XXX
    brown = Pat(4, 40, 3)
    cantus  <- brown.grouped(len)
  } yield {
    cantus ++ Pat(-1)
  }
  xs.flatten
}

Error for line marked XXX:

type mismatch;
 found   : (Playground.this.Pat[Int], Playground.this.Pat[Int])
 required: Playground.this.Pat[?]

Scala is 2.12.4

+6
source share
2 answers

This happens when you define mapan overly restrictive signature map[B](f: Pat[A] => Pat[B]). Recall that it is usually assumed that it accepts functions with an arbitrary type of result B, that is, it should be something like:

map[B](f: A => B): <stuff>

Now your understanding for the intermediate helper variable brown

  val xs = for {
    len     <- lPat.bubble
    brown = Pat(4, 40, 3)
    cantus  <- brown.grouped(len)
  } yield {
    cantus ++ Pat(-1)
  }

rewritten using mapin

  val xs = lPat.bubble.map(((len) => {
    val brown = Pat(4, 40, 3);
    scala.Tuple2(len, brown)
  })).flatMap(((x$1) => x$1: @scala.unchecked match {
    case scala.Tuple2((len @ _), (brown @ _)) => 
      brown.
        grouped(len).
        map(((cantus) => cantus.$plus$plus(Pat(-1))))
  }))

.

, map (Pat[A], Pat[Int]) ( (len, brown)) Pat[B] .

. , map map[B](f: Pat[A] => Pat[B]), . map. Pat[X] map f: X => Y Pat[Y] X Y, map.


: ...

, , - - CanPatFrom:

trait CanPatFrom[X, A] extends (X => Pat[A])

...
def map[X, B](f: Pat[A] => X)(implicit cpf: CanPatFrom[X, B]) = {
  val pb: Pat[B] = cpf(f(...))
  /* do your stuff here with `Pat[B]` instead of 
   * generic `X`
   */
  ...
}

, Pat - - ,

  • CanPatFrom[Pat[A], Pat[A]],
  • CanPatFrom[(Pat[A], Pat[B]), Pat[(A, B)]],
  • CanPatFrom[(Pat[A], Pat[B], Pat[C]), Pat[(A, B, C)]],
  • ...

map, , , , .

+8

, , implicits, , . , , A Pat[A1] A1. :

object Pats extends App {

  trait Pat[A]
  object Pat {
    def apply[A](elems: A*): Pat[A] = ???
  }

  implicit class PatOps[A](p: Pat[A]) {

    def ++(that: Pat[A]): Pat[A] = ???

    def bubble: Pat[Pat[A]] = ???

    def grouped(size: Pat[Int]): Pat[Pat[A]] = ???

    def map[B, A1, B1](f: A => B)
                      (implicit
                       ev1: A <:< Pat[A1],
                       ev2: B <:< Pat[B1]): Pat[B] = ???

    def flatMap[B, A1, B1](f: A => Pat[B])
                          (implicit
                           ev1: A <:< Pat[A1],
                           ev2: B <:< Pat[B1]): Pat[B] = ???

    def flatten[A1](implicit ev: A <:< Pat[A1]): Pat[A1] = ???
  }

  val lPat = Pat(1, 2, 3)
  val xs = for {
    len <- lPat.bubble
    cantus <- Pat(4, 40, 3).grouped(len)
  } yield cantus ++ Pat(-1)
  xs.flatten
}

, map flatMap. PatInternal .

+1

All Articles