2015-12-27 2 views
1

В Scala, если у вас есть выражение, содержащее знак подчеркивания, это анонимная функция с выражением как его тело и подчеркивание как его параметр, например. 2 * _ - анонимная функция, которая удваивает аргумент. Но как далеко простирается тело функции? Мне не хватает четкого правила здесь, что устраняет неоднозначность таких случаев, как например. следующее (проверено с Scala 2.11.7 РЕПЛ):Какой код содержит тело анонимной функции Scala с символом «_» (подчеркивание)?

scala> (_: Int)+2-1 // function body up to 1 - OK 
res7: Int => Int = <function1> 

scala> ((_: Int)+2)-1 // function body up to 2, - applied to function is an error 
<console>:11: error: value - is not a member of Int => Int 
    ((_: Int)+2)-1 
      ^
+3

В то время как вопрос не является дубликатом, принятый ответ на вопрос может быть применен непосредственно к этому вопросу: http://stackoverflow.com/questions/2173373/scala-foreach-strange-behaviour – sschaef

+0

Да, вопрос вы цитата отвечает на мой вопрос, говоря: «... правила расширения _. Он расширяется до самого внутреннего разделителя выражений (скобки или фигурные скобки)». Я могу только надеяться, однако, что эта цитата действительно содержит всю историю, так как я не совсем уверен, что эта цитата эквивалентна выражению spec «(2)», как цитирует Алексей Романов ниже (см. Мой комментарий там). Тем не менее, я бы принял ваш ответ как (надеюсь,!) Правильно, если бы можно было принять комментарий ;-) –

+0

Некоторые случаи, когда вам нужно быть осторожными с этим определением: 1. Он может расширяться дальше, чем ближайшие скобки/фигурные скобки: 'foo (1, _)', но в этом случае они не ограничивают 'Expr'. 2. В 'foo (_)' круглые скобки _do_ разграничить 'Expr', но он состоит только из самого раздела подчеркивания, и вам нужно посмотреть снаружи. 3. '=', '=>', ';', новая строка и ключевые слова, которые вы можете видеть вокруг 'Expr' в грамматике, также могут служить разделителями выражений. –

ответ

1

Определение дано в http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#placeholder-syntax-for-anonymous-functions, и это ... не так просто.

Выражение е синтаксической категории Expr связывает раздел подчеркивания и, если выполняются следующие два условия: (1) е правильно содержит и, и (2) не существует никакого другого выражение синтаксической категории Expr который является надлежащим содержащаяся в e и которая сама по себе содержит u.

Если выражение e связывает секции подчеркивания u_1, \ ldots, u_n в этом порядке, это эквивалентно анонимной функции (u'_1, ... u'_n) => e ', где каждый результат u_i от u_i, заменив символ подчеркивания свежим идентификатором, а e 'будет получен из e, заменив каждую секцию подчеркивания u_i на u_i'.

И если вы посмотрите на грамматику в начале раздела, (_: Int)+2 в (_: Int)+2-1 не является Expr, но в ((_: Int)+2)-1 это.

+0

ОК, из построения дерева синтаксического анализа (на бумаге), я вижу, что (_: Int) +2 анализирует как InfixExpr (но не более общее выражение, такое как Expr) при встраивании внутри (_: Int) +2+ 1, потому что только тогда его можно комбинировать с - 1 для формирования другого (более высокого уровня) InfixExpr. Таким образом, он не удовлетворяет требованию (2) спецификации, поскольку он не относится к категории Expr. В отличие от этого, (_: Int) +2 анализирует также как PostfixExpr, Expr1 и Expr при вложении в parens, как в ((_: ​​Int) +2) -1. Чтобы избежать этого анализа каждый раз, когда я использую _, я буду придерживаться правила «наружу до браслеса/пара» из приведенного выше вопроса. –

0
((_: Int)+2)-1 // function body up to 2, - applied to function is an error 

error: value - is not a member of Int => Int 
    ((_: Int)+2)-1 

Сообщение об ошибке от компилятора имеет смысл. Ваши дополнительные parens создали литерал функции, который добавляет '2' к параметру подстановочного знака/placeholder. Компилятор читает ваш код, означающий, что у вас есть это значение функции, и вы пытаетесь вычесть из него «1».

И это не имеет смысла. Вы можете отнести «1» от других чисел, но, конечно, не значение функции. Таким образом, компилятор говорит вам, что нет смысла вычитать его из значения функции. Или, в условиях компилятора, функция типа Int => Int не имеет функции '-'.

value - is not a member of Int => Int

Понимание этого сообщение об ошибке требует, чтобы вы знаете, что все операторы в Scala (-, *, + и т.д.) реализуются как методы типов. Если вы посмотрите на Scala API docs for Int, вы увидите, что он определяет длинный список методов с общими математическими и логическими символами оператора в качестве имен функций.

+0

chad, в то время как ваше объяснение сообщения об ошибке правильное, это был не мой вопрос (я знал об этом, так как мои комментарии к исходному коду «применяются к функциям» показывают). Вместо этого мне хотелось объяснить, какая часть выражения, содержащего знак подчеркивания, будет использоваться как тело функции (а не объяснение, почему ошибочная концепция размера тела функции приведет к ошибке компилятора). Однако неважно, что ваш ответ может быть полезен другим читателям. –

Смежные вопросы