I am relatively new to the Scala language, and I came across code that looks like this (while reviewing Akka).
val someFlow: Flow[Int, Int, NotUsed] = Flow[Int].reduce[Int](_ + _)
How can I read type annotations like: Flow[Int, Int, NotUsed]
?
I am relatively new to the Scala language, and I came across code that looks like this (while reviewing Akka).
val someFlow: Flow[Int, Int, NotUsed] = Flow[Int].reduce[Int](_ + _)
How can I read type annotations like: Flow[Int, Int, NotUsed]
?
Consider a value-level function application
((x: Int) => List(x))(42)
where value-lambda (x: Int) => List(x)
is applied to value argument 42
.
Consider a type-level function application
([X] =>> List[X])[Int]
where type-lambda [X] =>> List[X]
is applied to type argument Int
.
Now compare the two in
scala> val v: ([X] =>> List[X])[Int] = ((x: Int) => List(x))(42)
val v: List[Int] = List(42)
We see that a type lambda or type constructor constructs a proper type List[Int]
which accommodates a value List(42)
constructed by a value lambda or value constructor.
Note the similarity between =>
and =>>
. Now =>>
syntax is only available in Dotty (Scala 3) which brings type lambdas, however I believe it is already a helpful device to grok what types such as Flow[Int, Int, NotUsed]
really are
([In, Out, Mat] =>> Flow[In, Out, Mat])[Int, Int, NotUsed]
These are the facilities to support the techniques of polymorphism which allows us to think in ever higher levels of abstraction. For example, if f
takes a box of chocolates
def f(v: Box[Chocolate] = ???
then g
takes a box of something A
def g[A](v: Box[A]) = ???
and we can go even higher where h
takes some kind of container F
of something A
def h[F[_], A](v: F[A]) = ???
This last form of polymorphism is known as type constructor polymorphism and is what separates Scala from many other languages which stop at the box of something.