This page is no longer maintained — Please continue to the home page at www.scala-lang.org

underscore confusion

4 replies
Richard Rattigan
Joined: 2009-07-10,
User offline. Last seen 42 years 45 weeks ago.

Hi,

Can anyone explain this? I don't understand why the first line here
works, but the second doesn't. This seems to be an application of the
principle of maximum surprise.

List(1, 2, 3) map (List.range(1, _)) must beEqualTo(List(List(),
List(1), List(1, 2)))

List(1, 2, 3) map (List.range(1, _ + 1)) must beEqualTo(List(List(1),
List(1, 2), List(1, 2, 3)))
=> error: missing parameter type for expanded function ((x$11) =>
x$11.$plus(1))

Thanks,
Richard

Arthur Peters
Joined: 2009-01-09,
User offline. Last seen 42 years 45 weeks ago.
Re: underscore confusion
This is because "_ + 1" becomes a function and is passed to List.range(...). And since List.range does not take a function as a perameter the compiler cannot infer the anonymous functions type. That's where your compiler error comes from.

But I've run into something closely related that I thought I'd mention:

List(1,2,3).map(_+1)
res1: List[Int] = List(2, 3, 4)
List(1,2,3).map(2*_+1)
res2: List[Int] = List(3, 5, 7)
List(1,2,3).map((2*_)+1)
error: missing parameter type for expanded function ((x$1) => 2.*(x$1))
List(1,2,3).map((2*_)+1)
^
Why does the second line work? Shouldn't it be equivalent to the 3rd line. That being said it's nice to be able to use _ in more complex expressions, but it doesn't seem consistent.

-Arthur


On Mon, Aug 17, 2009 at 1:40 PM, Richard Rattigan <rattigan [at] broadinstitute [dot] org> wrote:
Hi,

Can anyone explain this? I don't understand why the first line here works, but the second doesn't. This seems to be an application of the principle of maximum surprise.

List(1, 2, 3) map (List.range(1, _)) must beEqualTo(List(List(), List(1), List(1, 2)))

List(1, 2, 3) map (List.range(1, _ + 1)) must beEqualTo(List(List(1), List(1, 2), List(1, 2, 3)))
  => error: missing parameter type for expanded function ((x$11) => x$11.$plus(1))


Thanks,
Richard


dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
Re: underscore confusion
When you use "_" as a place holder for an anonymous parameter of a function, the scope of that function is the innermost parenthesis containing it. Most of the time. For myself, I haven't been able to assert when that rule breaks. Some examples:   scala> (_)
<console>:1: error: unbound placeholder parameter
       (_)
        ^ scala> List.range(1, _)
<console>:5: error: missing parameter type for expanded function ((x$1) => List.range(1, x$1))
       List.range(1, _)
                     ^ scala> List.range(1, _ + 1)
<console>:5: error: missing parameter type for expanded function ((x$1) => x$1.$plus(1))
       List.range(1, _ + 1)
                     ^ scala> List(1,2,3) map (_)
<console>:5: error: missing parameter type for expanded function ((x$1) => List(1, 2, 3).map(x$1))
       List(1,2,3) map (_)
                        ^ scala> List(1,2,3) map (List(_))
res3: List[List[Int]] = List(List(1), List(2), List(3)) scala> List(1,2,3).map(_)
<console>:5: error: missing parameter type for expanded function ((x$1) => List(1, 2, 3).map(x$1))
       List(1,2,3).map(_)
                       ^ scala> List(1,2,3).map((_))
<console>:5: error: missing parameter type for expanded function ((x$1) => List(1, 2, 3).map(x$1))
       List(1,2,3).map((_))
                        ^ scala> List(1,2,3).map(((_)))
<console>:5: error: missing parameter type for expanded function ((x$1) => List(1, 2, 3).map(x$1))
       List(1,2,3).map(((_)))
                         ^   So, in Richard's case, "_" alone as a parameter is treated as an anonymous parameter _outside_ that particular method, but as soon as something else is in that parameter, the scope of the function become the parameter itself.   On your case, Arthur, "(2*_)" becomes "((x$1) => 2*x$1)", and the whole expression becomes, then, roughly speaking:   List(1,2,3).map((x$0) => ((x$1) => 2*x$1) + 1)   On Mon, Aug 17, 2009 at 2:49 PM, Arthur Peters <arthur [dot] peters [at] gmail [dot] com> wrote:
This is because "_ + 1" becomes a function and is passed to List.range(...). And since List.range does not take a function as a perameter the compiler cannot infer the anonymous functions type. That's where your compiler error comes from.

But I've run into something closely related that I thought I'd mention:

List(1,2,3).map(_+1)
res1: List[Int] = List(2, 3, 4)
List(1,2,3).map(2*_+1)
res2: List[Int] = List(3, 5, 7)
List(1,2,3).map((2*_)+1)
error: missing parameter type for expanded function ((x$1) => 2.*(x$1))
List(1,2,3).map((2*_)+1)
^
Why does the second line work? Shouldn't it be equivalent to the 3rd line. That being said it's nice to be able to use _ in more complex expressions, but it doesn't seem consistent.

-Arthur


On Mon, Aug 17, 2009 at 1:40 PM, Richard Rattigan <rattigan [at] broadinstitute [dot] org> wrote:
Hi,

Can anyone explain this? I don't understand why the first line here works, but the second doesn't. This seems to be an application of the principle of maximum surprise.

List(1, 2, 3) map (List.range(1, _)) must beEqualTo(List(List(), List(1), List(1, 2)))

List(1, 2, 3) map (List.range(1, _ + 1)) must beEqualTo(List(List(1), List(1, 2), List(1, 2, 3)))
  => error: missing parameter type for expanded function ((x$11) => x$11.$plus(1))


Thanks,
Richard





--
Daniel C. Sobral

Something I learned in academia: there are three kinds of academic reviews: review by name, review by reference and review by value.
Arthur Peters
Joined: 2009-01-09,
User offline. Last seen 42 years 45 weeks ago.
Re: underscore confusion
I know that (_*2) desugars to "x=>x*2". What seems odd is that "2*_+1" desugars differently from "(2*_)+1". These two expression seem like they should be in all ways equivalent because of operator precedence.

My issue is that it looks like "2*_+1" (or even "2*_+1 min 30") is treated as one expression with multiple method applications. What is the rule that defines the bounds of the placeholder binding? I've looked a bit in the spec and it isn't clear to me.

-Arthur


On Mon, Aug 17, 2009 at 3:24 PM, Daniel Sobral <dcsobral [at] gmail [dot] com> wrote:
When you use "_" as a place holder for an anonymous parameter of a function, the scope of that function is the innermost parenthesis containing it. Most of the time. For myself, I haven't been able to assert when that rule breaks. Some examples:   scala> (_)
<console>:1: error: unbound placeholder parameter
       (_)
        ^ scala> List.range(1, _)
<console>:5: error: missing parameter type for expanded function ((x$1) => List.range(1, x$1))
       List.range(1, _)
                     ^ scala> List.range(1, _ + 1)
<console>:5: error: missing parameter type for expanded function ((x$1) => x$1.$plus(1))
       List.range(1, _ + 1)
                     ^ scala> List(1,2,3) map (_)
<console>:5: error: missing parameter type for expanded function ((x$1) => List(1, 2, 3).map(x$1))
       List(1,2,3) map (_)
                        ^ scala> List(1,2,3) map (List(_))
res3: List[List[Int]] = List(List(1), List(2), List(3)) scala> List(1,2,3).map(_)
<console>:5: error: missing parameter type for expanded function ((x$1) => List(1, 2, 3).map(x$1))
       List(1,2,3).map(_)
                       ^ scala> List(1,2,3).map((_))
<console>:5: error: missing parameter type for expanded function ((x$1) => List(1, 2, 3).map(x$1))
       List(1,2,3).map((_))
                        ^ scala> List(1,2,3).map(((_)))
<console>:5: error: missing parameter type for expanded function ((x$1) => List(1, 2, 3).map(x$1))
       List(1,2,3).map(((_)))
                         ^   So, in Richard's case, "_" alone as a parameter is treated as an anonymous parameter _outside_ that particular method, but as soon as something else is in that parameter, the scope of the function become the parameter itself.   On your case, Arthur, "(2*_)" becomes "((x$1) => 2*x$1)", and the whole expression becomes, then, roughly speaking:   List(1,2,3).map((x$0) => ((x$1) => 2*x$1) + 1)   On Mon, Aug 17, 2009 at 2:49 PM, Arthur Peters <arthur [dot] peters [at] gmail [dot] com> wrote:
This is because "_ + 1" becomes a function and is passed to List.range(...). And since List.range does not take a function as a perameter the compiler cannot infer the anonymous functions type. That's where your compiler error comes from.

But I've run into something closely related that I thought I'd mention:

List(1,2,3).map(_+1)
res1: List[Int] = List(2, 3, 4)
List(1,2,3).map(2*_+1)
res2: List[Int] = List(3, 5, 7)
List(1,2,3).map((2*_)+1)
error: missing parameter type for expanded function ((x$1) => 2.*(x$1))
List(1,2,3).map((2*_)+1)
^
Why does the second line work? Shouldn't it be equivalent to the 3rd line. That being said it's nice to be able to use _ in more complex expressions, but it doesn't seem consistent.

-Arthur


On Mon, Aug 17, 2009 at 1:40 PM, Richard Rattigan <rattigan [at] broadinstitute [dot] org> wrote:
Hi,

Can anyone explain this? I don't understand why the first line here works, but the second doesn't. This seems to be an application of the principle of maximum surprise.

List(1, 2, 3) map (List.range(1, _)) must beEqualTo(List(List(), List(1), List(1, 2)))

List(1, 2, 3) map (List.range(1, _ + 1)) must beEqualTo(List(List(1), List(1, 2), List(1, 2, 3)))
  => error: missing parameter type for expanded function ((x$11) => x$11.$plus(1))


Thanks,
Richard





--
Daniel C. Sobral

Something I learned in academia: there are three kinds of academic reviews: review by name, review by reference and review by value.

dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
Re: underscore confusion
As I told you, the rule is that the parenthesis delimit the expression. Expressions are recursive, so you an place one inside another. There are two expressions in "(2*_)+1" and one in "2*_+1 min 30".

On Tue, Aug 18, 2009 at 1:23 AM, Arthur Peters <arthur [dot] peters [at] gmail [dot] com> wrote:
I know that (_*2) desugars to "x=>x*2". What seems odd is that "2*_+1" desugars differently from "(2*_)+1". These two expression seem like they should be in all ways equivalent because of operator precedence.

My issue is that it looks like "2*_+1" (or even "2*_+1 min 30") is treated as one expression with multiple method applications. What is the rule that defines the bounds of the placeholder binding? I've looked a bit in the spec and it isn't clear to me.

-Arthur


On Mon, Aug 17, 2009 at 3:24 PM, Daniel Sobral <dcsobral [at] gmail [dot] com> wrote:
When you use "_" as a place holder for an anonymous parameter of a function, the scope of that function is the innermost parenthesis containing it. Most of the time. For myself, I haven't been able to assert when that rule breaks. Some examples:   scala> (_)
<console>:1: error: unbound placeholder parameter
       (_)
        ^ scala> List.range(1, _)
<console>:5: error: missing parameter type for expanded function ((x$1) => List.range(1, x$1))
       List.range(1, _)
                     ^ scala> List.range(1, _ + 1)
<console>:5: error: missing parameter type for expanded function ((x$1) => x$1.$plus(1))
       List.range(1, _ + 1)
                     ^ scala> List(1,2,3) map (_)
<console>:5: error: missing parameter type for expanded function ((x$1) => List(1, 2, 3).map(x$1))
       List(1,2,3) map (_)
                        ^ scala> List(1,2,3) map (List(_))
res3: List[List[Int]] = List(List(1), List(2), List(3)) scala> List(1,2,3).map(_)
<console>:5: error: missing parameter type for expanded function ((x$1) => List(1, 2, 3).map(x$1))
       List(1,2,3).map(_)
                       ^ scala> List(1,2,3).map((_))
<console>:5: error: missing parameter type for expanded function ((x$1) => List(1, 2, 3).map(x$1))
       List(1,2,3).map((_))
                        ^ scala> List(1,2,3).map(((_)))
<console>:5: error: missing parameter type for expanded function ((x$1) => List(1, 2, 3).map(x$1))
       List(1,2,3).map(((_)))
                         ^   So, in Richard's case, "_" alone as a parameter is treated as an anonymous parameter _outside_ that particular method, but as soon as something else is in that parameter, the scope of the function become the parameter itself.   On your case, Arthur, "(2*_)" becomes "((x$1) => 2*x$1)", and the whole expression becomes, then, roughly speaking:   List(1,2,3).map((x$0) => ((x$1) => 2*x$1) + 1)   On Mon, Aug 17, 2009 at 2:49 PM, Arthur Peters <arthur [dot] peters [at] gmail [dot] com> wrote:
This is because "_ + 1" becomes a function and is passed to List.range(...). And since List.range does not take a function as a perameter the compiler cannot infer the anonymous functions type. That's where your compiler error comes from.

But I've run into something closely related that I thought I'd mention:

List(1,2,3).map(_+1)
res1: List[Int] = List(2, 3, 4)
List(1,2,3).map(2*_+1)
res2: List[Int] = List(3, 5, 7)
List(1,2,3).map((2*_)+1)
error: missing parameter type for expanded function ((x$1) => 2.*(x$1))
List(1,2,3).map((2*_)+1)
^
Why does the second line work? Shouldn't it be equivalent to the 3rd line. That being said it's nice to be able to use _ in more complex expressions, but it doesn't seem consistent.

-Arthur


On Mon, Aug 17, 2009 at 1:40 PM, Richard Rattigan <rattigan [at] broadinstitute [dot] org> wrote:
Hi,

Can anyone explain this? I don't understand why the first line here works, but the second doesn't. This seems to be an application of the principle of maximum surprise.

List(1, 2, 3) map (List.range(1, _)) must beEqualTo(List(List(), List(1), List(1, 2)))

List(1, 2, 3) map (List.range(1, _ + 1)) must beEqualTo(List(List(1), List(1, 2), List(1, 2, 3)))
  => error: missing parameter type for expanded function ((x$11) => x$11.$plus(1))


Thanks,
Richard





--
Daniel C. Sobral

Something I learned in academia: there are three kinds of academic reviews: review by name, review by reference and review by value.




--
Daniel C. Sobral

Something I learned in academia: there are three kinds of academic reviews: review by name, review by reference and review by value.

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland