Scala «постфиксные операции»

Мы искали полчаса, но до сих пор не можем понять.

ВSIP: модульные языковые функции Есть ряд функций, которые потребуют явного "что позволяет» в Scala 2.10 (import language.feature). Среди них естьpostfixOps, на который я просто нигде не могу найти ссылку. Что именно позволяет эта функция?

 user50059215 янв. 2013 г., 02:31
Я боюсь, что план на 2.11 года состоит в том, что вместо просто предупреждений результатом будут ошибки компиляции. Насколько я понял, текущее состояние с предупреждениями просто "легкость» переход...
 AmigoNico10 февр. 2013 г., 23:21
Добавьте -language: postfixOps в командную строку scalac, и все будет так, как было раньше - импорт не требуется, предупреждений нет. В build.sbt просто добавьте это в свой scalacOptions Seq.
 Alex25 июн. 2014 г., 23:20
Вы не должны использовать его в современных программах, неЯ подавил это предупреждение, я описал почему. Пожалуйста, проверьте это.
 dmitry22 окт. 2012 г., 15:52
Наконец, кажется, что компилятор компилируется, несмотря на выдачу предупреждений. Так что, может быть, такой, как я, может просто игнорировать эти раздражающие предупреждения.
 dmitry15 янв. 2013 г., 15:01
Это отстой, я все еще нене понимаю почемуpostfix ops находится в одном ведре с действительно мощными вещами, такими как имплициты или экзистенциальные типы. Пытался спросить на SIP'естраницу, но ответа нет.

Ответы на вопрос(3)

Самый простой ответ:

Удаление точки из методов без параметровDEPRECATED!

List(1,2,3) reverse //is bad style and will lead to unpredicted behaviour
List(1,2,3) map(_*2) reverse //bad too, because reverse can take first method call from the next line (details below)

ОК, чтобы удалить точку в методах, которые принимают один параметрфункция высшего порядка как карта, фильтр, считать и быть в безопасности! Также,чисто функциональный такие методы, как почтовый индекс

List(1,2,3) map(_*2) filter(_>2)
(List(1,2,3) map(_*2)).reverse //safe and good
List(1,3,5) zip List(2,4,6)

Длинный ответ ПОЧЕМУ

case class MyBool(x: Boolean) {
  def !!! = MyBool(!x) //postfix
  def or(other: MyBool): MyBool = if(x) other else this //infix
  def justMethod0() = this //method with empty parameters
  def justMethod2(a: MyBool, b: MyBool) = this //method with two or more
  override def toString = if(x) "true" else "false"
}

1) Оператор Postfix - это на самом деле вызов метода без параметров (a! == a.!) И без скобок. (считается небезопасным и не рекомендуется)

val b1 = MyBool(false) !!!
List(1,2,3) head

2) Постфиксный оператор - это метод, который должен завершать строку, иначе он будет рассматриваться как инфикс.

val b1 = MyBool(true) no! no! //ERROR
//is actually parsed like
val b2 = MyBool(true).no!(no!) //(no!) is unknown identifier
//as bad as
Vector(1,2,3) toList map(_*2) //ERROR

3) Инфиксный оператор - это метод с одним параметром, который можно вызывать без точки и скобок. Только длячисто функциональный методы

val c1 = MyBool(true) or b1 or MyBool(true)
val c2 = MyBool(true).or(b1).or(MyBool(true))
c1 == c2

4) Метод с одним или несколькими параметрами будет цепочкой без точки, если вы вызываете его с параметрами. def a (), def a (x), def a (x, y) Но вы должны делать это только для методов, которые используютфункция высшего порядка как параметр!

val d1 = MyBool(true) justMethod2(b1, c1) or b1 justMethod0() justMethod2(c1, b1)
//yes, it works, but it may be confusing idea
val d2 = MyBool(true).justMethod2(b1,c1).or(b1).justMethod0().justMethod2(c1, b1)
d1 == d2
//looks familiar? This is where it should be used:
List(1,2,3) filter(_>1) map(_*2)

Пример предупреждения:

предупреждение: было 1 предупреждение об устаревании; перезапустите с -deprecation для предупреждения о подробностях: хвост оператора postfix должен быть включен, сделав неявное значение scala.language.postfixOps видимым. Этого можно достичь, добавив условие импортаimport scala.language.postfixOps ' или установив опцию компилятора -language: postfixOps. См. Документацию Scala для значения scala.language.postfixOps для обсуждения, почему эта функция должна быть явно включена.

Решение Вопроса

ии. Например

List(1,2,3) tail

скорее, чем

List(1,2,3).tail

В этом безвредном примере это не проблема, но это может привести к неясностям. Это не скомпилирует:

val appender:List[Int] => List[Int] = List(1,2,3) ::: //add ; here
List(3,4,5).foreach {println}

И сообщение об ошибке не очень полезно:

    value ::: is not a member of Unit

Пытается вызвать::: метод на результатforeach вызов, который имеет типUnit, Это, вероятно, не то, что задумал программист. Чтобы получить правильный результат, вам нужно вставить точку с запятой после первой строки.

 Kim Stebel22 окт. 2012 г., 14:24
@dmitry: Добавлено объяснение, почему это может быть хорошей идеей.
 dmitry22 окт. 2012 г., 14:38
В вашем примере нет постфиксных операций. Это просто неоднозначная семантика в инфиксных обозначениях. Или где мне не хватает этого?
 Kim Stebel22 окт. 2012 г., 15:14
@dmitry: с; !
 som-snytt25 мая 2013 г., 03:16
+1 за интересный пример в appender. Это должен быть скальпуззлер.
 Kim Stebel22 окт. 2012 г., 14:34
Да, я уверен. Просто попробуйте. RC1 только предупреждает вас.
 dmitry22 окт. 2012 г., 15:09
@Debilski Не уверен, что я понимаю, что тымы подразумевали под этим $, но без $List(1,2,3) map (_ * 2) filter (_ != 2) reverse работает точно так, как ожидалось и производитList(6, 4) и без постфикса ops это будет:(List(1,2,3) map (_ * 2) filter (_ != 2)).reverse? Это лучше?
 dmitry22 окт. 2012 г., 14:20
Боже мой ... мне так понравилось, и теперь ям вынужден на место идиотскийimport language.postfixOps или используйте точки везде. Почему это???!!!
 dmitry22 окт. 2012 г., 14:48
Во всяком случае, пример не о постфиксе. Это точка, которая имеет более высокий приоритет, чем нотация метода без точки.
 dmitry22 окт. 2012 г., 15:04
@ kim-stebel И на этом этапе я должен сказать, что, несмотря на ваш общий ответ, правильный, но пример довольно запутанный. И реГис Жан-Жиль прав, потому что постфиксная запись означаетОператор идет после операндов, А в scala это может быть просто, если список аргументов пуст. В вашем примере это карри. И хотя это выдает предупреждение (если; добавлено), очевидно, что происходит. Может лучше использовать подстановочный знак для второго аргумента? Кстати, этот пример действительно сбивает с толку. Потому что без; и включив postfixOps, он выдаст ту же ошибку, но без предупреждения.
 Debilski22 окт. 2012 г., 14:48
Было бы неплохо (но еще более запутанно), если бы у Scala была альтернатива для более низкого приоритета., Тогда мы могли бы иметьList(1,2,3) map (_ * 2) filter (_ != 2) $ reverse и обменять$ для точек или скобок.
 Kim Stebel22 окт. 2012 г., 14:28
@dmitry: также ты неЧтобы добавить импорт к каждому файлу, вы можете просто использовать переключатель компилятора и установить его один раз для всего проекта.
 dmitry22 окт. 2012 г., 14:27
На самом деле этот SIP 18 - это первое, что действительно раздражает и вызывает споры в scala. Если бы я мог представить, что структурная типизация и экзистенциалы, и даже неявные преобразования используются не очень часто в повседневном коде, но в постфиксном синтаксисе ... Я использую его везде, где это возможно.
 dmitry22 окт. 2012 г., 14:35
Да, переключение компилятора - это спасение, но это раздражает. Если он находится в скрипте сборки, никто никогда не узнает об этом, но если я хочу просто скомпилировать файл, я должен предоставить эти ключи компилятора вручную. И все забывают такие вещи. Это значит, что я всегда буду раздражаться. И это плохо, потому что скала никогда не раздражала меня раньше.
 dmitry22 окт. 2012 г., 14:32
Вы уверены, что этот пример о postfix ops? Я могу легко привести пример, где это полезно. Сказать:List(1,2,3) map { _ + 1 } reverse гораздо читабельнее (имхо, конечно) чемList(1,2,3).map( _ + 1).reverse
 dmitry22 окт. 2012 г., 14:52
@ Ким-Стебель, ямы сделали. Нет предупреждения Просто ошибка::7: error: value ::: is not a member of Unit, И только потому, чтоList(3,4,5).foreach {println} был выполнен первым и произведенUnit, Постфикс не задействован.
 Kim Stebel22 окт. 2012 г., 14:51
@dmitry: Конечно, речь идет о postfix. Вы также можете исправить ошибку компилятора, изменив вызов на::: расставить точки синтаксиса вместо постфикса. Буду игнорировать дальнейшие комментарии от вас, пока их качество не улучшится.
 Kim Stebel22 окт. 2012 г., 14:45
@dmitry: просто скомпилируйте его с 2.10.0-RC1, и вы увидите это предупреждение: постфиксный оператор ::: следует включить [warn], сделав видимым неявное значение language.postfixOps. [предупреждение] Этого можно достичь, добавив условие импорта 'import language.postfixOps ' [предупреждение] или установкой параметра компилятора -language: postfixOps.
 dmitry22 окт. 2012 г., 15:26
@KimStebel С; Пример выдает предупреждение. Но без ошибок. И это просто путаница какого-то другого рода. Просто потому, что кто-то хочет карри методы без подстановочного знака вместо параметра. Это едва достаточное объяснение, почему postfixOps - плохая идея.

пустого списка аргументов) метода как постфиксного оператора:

К примеру:

case class MyBool(value: Boolean) {
    def negated = new MyBool(!value)
}
val b1 = MyBool( true )
val b2 = b1 negated // Same as b1.negated

Увидеть:http://www.scala-lang.org/node/118

 Régis Jean-Gilles22 окт. 2012 г., 14:35
Я не уверен, чтобы увидеть, какой пример вы ссылаетесь. В любом случае, я думаю, что если вы хотите придираться, это также будет работать с ненулевыми методами, где все параметры имеют значения по умолчанию. В любом случае, я просто перефразировал официальную документацию по scala (см. Ссылку): "Как показано в первой строке этого кода, в качестве постфиксных операторов также можно использовать нулевые методы ».
 Régis Jean-Gilles22 окт. 2012 г., 14:54
Справедливо. Я проверил, и похоже, что postfixOps охватывает и этот случай, хотя для меня они довольно разные (ваш пример показывает, какmyObject.myMethod можно молча относиться так же, какmyObject.myMethod _).
 Kim Stebel22 окт. 2012 г., 14:24
Как показывает мой второй пример, он не ограничивается нулевыми методами.
 Kim Stebel22 окт. 2012 г., 14:36
Нет, значения по умолчанию не нужны. Я имею в виду пример в моем ответе, конкретно на строкуval appender:List[Int] => List[Int] = List(1,2,3) :::,::: Метод не является нулевым и не имеет значений по умолчанию.
 som-snytt25 мая 2013 г., 03:17
+1 за раздел комментариев, который 'более привлекательным [для меня], чем ответ.

Ваш ответ на вопрос