Понимание оператора вызова и вызова метода infix (::) в Scala
Я новичок в языке программирования Scala и пытался что-то затеять в уме, когда я следил за лекциями на здесь.
Я думаю, что не мог понять, как работает оператор cons, вот некоторые вещи, которые я пробовал:
Я создал генератор псевдослучайных чисел, затем попытался создать список из одного случайного значения:
scala> val gen = new java.util.Random
gen: java.util.Random = [email protected]
scala> gen nextInt 3 :: Nil
<console>:7: error: type mismatch;
found : List[Int]
required: Int
gen nextInt 3 :: Nil
^
Но он попытался передать List (3) методу nextnt. Когда я использовал паратесы, проблем не было.
scala> (gen nextInt 3) :: Nil
res69: List[Int] = List(1)
Мне было интересно узнать о порядке выполнения, поэтому я создал функцию для проверки
scala> def pr(i:Int):Int = { println(i); i }
pr: (i: Int)Int
scala> pr(1) :: pr(2) :: pr(3) :: Nil
1
2
3
res71: List[Int] = List(1, 2, 3)
Как видно из выходов, порядок выполнения совпадает с порядком появления. Тогда я подумал, что это может быть о функции nextInt, после чего я попытался выполнить следующие действия:
scala> 1 + 2 :: Nil
res72: List[Int] = List(3)
Он сначала выполнил дополнение, и после этого выполнено cons. Итак, вот вопрос: в чем разница между gen nextInt 3 :: Nil
и 1 + 2 :: Nil
?
Ответы
Ответ 1
Здесь есть две вещи: приоритет и fixity. Как упоминалось в sepp2k, этот вопрос о переполнении стека объясняет приоритет, считая, что правила, как указано, недостаточно полны, и произошли очень небольшие изменения от Scala 2.7 до Scala 2.8. Однако различия относятся главным образом к операторам, заканчивающимся на =
.
Что касается фиксации, то почти все в Scala читается слева направо, для чего используются программисты. Однако в Scala операторы, заканчивающиеся на :
, читаются справа налево.
Возьмем, таким образом, этот пример:
1 + 2 :: Nil
Во-первых, приоритет. Что имеет наибольшее преимущество, +
или :
? Согласно таблице +
имеет приоритет над :
, поэтому добавление выполняется в первую очередь. Следовательно, выражение равно этому:
((1).+(2)) :: Nil
Теперь нет конфликта приоритетов, но поскольку ::
заканчивается на :
, он имеет различную фиксацию. Он читается справа налево, поэтому:
Nil.::((1).+(2))
С другой стороны, в этом:
gen nextInt 3 :: Nil
Оператор ::
имеет приоритет над nextInt
, поскольку :
имеет приоритет над всеми буквами. Поэтому, помня о его фиксации, он становится:
gen nextInt Nil.::(3)
Что тогда становится
gen.nextInt(Nil.::(3))
В этот момент ошибка очевидна.
PS: Я пишу (1).+(2)
вместо 1.+(2)
, потому что на момент написания этой статьи 1.
интерпретируется как двойное число, делая 1.+(2)
выражение infix, добавляющее double 1.0 to 2. Этот синтаксис устарел как Scala 2.10.0 и, вероятно, не будет присутствовать на Scala 2.11.
Ответ 2
Это о приоритете, а не порядке выполнения. +
имеет более высокий приоритет, чем ::
, поэтому a + b :: c
анализируется как (a + b) :: c
. Однако вызовы метода infix с регулярными именами имеют более низкий приоритет, поэтому a foo b c
анализирует как a foo (b c)
.
См. этот вопрос для списка операторов, упорядоченных по их приоритету в scala.