Confusing scala syntax

只愿长相守 提交于 2021-01-28 02:10:42

问题


trying to understand some scala syntax, and where to find their spec. Bellow i am confused about statefulMapConcat.

The signature is this one:

def statefulMapConcat[T](f: () => Out => immutable.Iterable[T]): Repr[T]

and we have

"be able to restart" in {
      Source(List(2, 1, 3, 4, 1))
        .statefulMapConcat(() => {
          var prev: Option[Int] = None
          x => {
            if (x % 3 == 0) throw ex
            prev match {
              case Some(e) =>
                prev = Some(x)
                (1 to e).map(_ => x)
              case None =>
                prev = Some(x)
                List.empty[Int]
            }
          }
        })
        .withAttributes(ActorAttributes.supervisionStrategy(Supervision.restartingDecider))
        .runWith(TestSink.probe[Int])
        .request(2)
        .expectNext(1, 1)
        .request(4)
        .expectNext(1, 1, 1, 1)
        .expectComplete()
    }

I do not under well how

{
          var prev: Option[Int] = None
          x => {
            if (x % 3 == 0) throw ex
            prev match {
              case Some(e) =>
                prev = Some(x)
                (1 to e).map(_ => x)
              case None =>
                prev = Some(x)
                List.empty[Int]
            }
          }

correspond to

Out => immutable.Iterable[T]

Can someone decompose it for me please ?

in my mind x would correspond to Out, but then we have the declaration of a variable before var prev: Option[Int] = None

I would like to understand and where to find explanation about those scala magic in general


回答1:


Two key concepts to understand here are

  • the value of the whole block expression is the value of the last expression in the block, and
  • functions are first-class values

Consider the following block expression

{
  var prev: Option[Int] = None
  42 // I am the last value of the block
}

Because the last expression in the block evaluates to value 42, the value of the whole block is 42 of type Int.

Similarly, consider the following block expression

{
  var prev: Option[Int] = None
  (x: Int) => { x + 1 } // I am also the last *value* of the block
}

Because the last expression in the block evaluates to value (x: Int) => { x + 1 }, the value of the whole block is value (x: Int) => { x + 1 } of type Int => Int.

In both cases, because expression var prev: Option[Int] = None is not the last expression in the block, it does not affect the type of the value of the whole block.




回答2:


Quick illustration. Actually, no interior braces when you write the single arg as a block:

scala> def f(g: () => String => Int) = g()("42")
f: (g: () => String => Int)Int

scala> f(() => _.toInt)
res0: Int = 42

scala> f { () => s => s.toInt }
res1: Int = 42

scala> f ( () => s => s.toInt )
res2: Int = 42

scala> f { val x = "0" ; () => val y = x + "0" ; s => (s+y).toInt }
res3: Int = 4200

Showing with -Vprint:parser (-Xprint on 2.12) that it parses correctly, even though the semicolons might fool the eye:

    val res3 = f({
      val x = "0";
      (() => {
        val y = x.$plus("0");
        ((s) => s.$plus(y).toInt)
      })
    })

Edit: the magically captured var is on the heap:

scala> { var i = 42 ; (j: Int) => j + i }
res1: Int => Int = $$Lambda$892/0x00000001006ec840@6e981e78

scala> :javap -c -
Compiled from "<console>"
public class $line4.$read$$iw$$iw$ {
  public static final $line4.$read$$iw$$iw$ MODULE$;

  public static {};
    Code:
       0: new           #2                  // class $line4/$read$$iw$$iw$
       3: dup
       4: invokespecial #25                 // Method "<init>":()V
       7: putstatic     #27                 // Field MODULE$:L$line4/$read$$iw$$iw$;
      10: bipush        42
      12: invokestatic  #33                 // Method scala/runtime/IntRef.create:(I)Lscala/runtime/IntRef;
      15: astore_0
      16: aload_0
      17: invokedynamic #52,  0             // InvokeDynamic #0:apply$mcII$sp:(Lscala/runtime/IntRef;)Lscala/runtime/java8/JFunction1$mcII$sp;
      22: putstatic     #54                 // Field res1:Lscala/Function1;
      25: return

  public scala.Function1<java.lang.Object, java.lang.Object> res1();
    Code:
       0: getstatic     #54                 // Field res1:Lscala/Function1;
       3: areturn

  public static final int $anonfun$res1$1(scala.runtime.IntRef, int);
    Code:
       0: iload_1
       1: aload_0
       2: getfield      #65                 // Field scala/runtime/IntRef.elem:I
       5: iadd
       6: ireturn

  public $line4.$read$$iw$$iw$();
    Code:
       0: aload_0
       1: invokespecial #66                 // Method java/lang/Object."<init>":()V
       4: return
}


来源:https://stackoverflow.com/questions/59462539/confusing-scala-syntax

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!