Why Scala Does Not Allow ListMap _ and Signature Type in REPL

Background

I recently visited a newbie Scala meetup, and we talked about the difference between methods and functions (also discussed in detail here ).

For instance:

scala> val one = 1 one: Int = 1 scala> val addOne = (x: Int) => x + 1 addOne: Int => Int = <function1> 

This demonstrates that vals can not only have an integer type, but also have a function type. We can see the type in Scala repl:

 scala> :type addOne Int => Int 

We can also define methods in objects and classes:

 scala> object Foo { | def timesTwo(op: Int) = op * 2 | } defined module Foo 

And although the method has no type (but rather has a type signature), we can raise it to a function to see what it is:

 scala> :type Foo.timesTwo <console>:9: error: missing arguments for method timesTwo in object Foo; follow this method with `_' if you want to treat it as a partially applied function Foo.timesTwo ^ scala> :type Foo.timesTwo _ Int => Int 

So far so good. We even talked about how functions are actually objects using the method and how we can de-syntactic expressions for sugar to show this:

 scala> Foo.timesTwo _ apply(4) res0: Int = 8 scala> addOne.apply(3) res1: Int = 4 

For me, this is very useful when learning a language, because I can learn what syntax means.

Problem example

However, we were faced with a situation that we could not identify. Take, for example, a list of strings. We can display functions over values โ€‹โ€‹that demonstrate the basic Scala collections and functional programming:

 scala> List(1,2,3).map(_*4) res2: List[Int] = List(4, 8, 12) 

So what is the type of List (1,2,3) .map ()? I would expect us to do the same: a type trick in repl:

 scala> :type List(1,2,3).map _ <console>:8: error: Cannot construct a collection of type Nothing with elements of type Nothing based on a collection of type List[Int]. List(1,2,3).map _ ^ 

From the API definition, I know the signature is:

 def map[B](f: (A) โ‡’ B): List[B] 

But there is also a complete signature:

 def map[B, That](f: (A) โ‡’ B)(implicit bf: CanBuildFrom[List[A], B, That]): That 

Question

So, there are two things that I do not quite understand:

  • Why doesn't the normal actuation function work in ListMap? Is there a way for de-syntactic sugar to make an erroneous statement to demonstrate what is happening?
  • If the reason the method cannot be taken off is caused by a full โ€œimplicitโ€ signature, what exactly happens there?

Finally, is there a reliable way to check both types and signatures from REPL?

+4
source share
2 answers

The problem you are facing is that the Scala functions are monomorphic, and the methods can be polymorphic . As a result, parameters of type B and That must be known in order to create a function value for List.map .

The compiler is trying to infer parameters, but cannot come up with anything reasonable. If you specify parameters, you will get a valid function type:

 scala> List(1,2,3).map[Char, List[Char]] _ res0: (Int => Char) => List[Char] = <function1> scala> :type res0 (Int => Char) => List[Char] 
+7
source

Without the actual function argument, the intended function type is Int => Nothing , but the target collection is also Nothing . There is no suitable CanBuildFrom[List[Int], Nothing, Nothing] scope that we can see by implicitly[CanBuildFrom[List[Int], Nothing, Nothing]] in the REPL (the same error appears). If you specify type parameters, you can get a function:

 scala> :type List(1,2,3).map[Int, List[Int]] _ (Int => Int) => List[Int] 

I don't think you can check method signatures in REPL. This is what Scaladoc is for.

+1
source

Source: https://habr.com/ru/post/1501739/


All Articles