Skip to content

Commit 27760ce

Browse files
Refresh multiple-parameter-lists.md in russian (scala#2836)
1 parent 7b755ce commit 27760ce

File tree

1 file changed

+190
-43
lines changed

1 file changed

+190
-43
lines changed

_ru/tour/multiple-parameter-lists.md

Lines changed: 190 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,77 +8,224 @@ next-page: case-classes
88
previous-page: nested-functions
99
---
1010

11-
Методы могут объявляться с несколькими списками параметров. При этом когда такой метод вызывается с меньшим количеством списков параметров, это приводит к созданию новой функции, которая ожидает на вход не достающий список параметров. Формально это называется [частичное применение](https://en.wikipedia.org/wiki/Partial_application).
11+
Методы могут объявляться с несколькими списками параметров.
1212

13-
Например,
14-
15-
```scala mdoc
16-
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
17-
val numberFunc = numbers.foldLeft(List[Int]()) _
13+
### Пример
1814

19-
val squares = numberFunc((xs, x) => xs :+ x*x)
20-
print(squares) // List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
15+
Вот пример, определенный для трейта `Iterable` из API Scala коллекций:
2116

22-
val cubes = numberFunc((xs, x) => xs :+ x*x*x)
23-
print(cubes) // List(1, 8, 27, 64, 125, 216, 343, 512, 729, 1000)
17+
{% tabs foldLeft_definition class=tabs-scala-version %}
18+
19+
{% tab 'Scala 2' for=foldLeft_definition %}
20+
21+
```scala
22+
trait Iterable[A] {
23+
...
24+
def foldLeft[B](z: B)(op: (B, A) => B): B
25+
...
26+
}
2427
```
2528

26-
Рассмотрим такие примеры из класса [Traversable](/overviews/collections/trait-traversable.html) коллекции Scala:
29+
{% endtab %}
2730

28-
```scala mdoc:fail
31+
{% tab 'Scala 3' for=foldLeft_definition %}
32+
33+
```scala
34+
trait Iterable[A]:
35+
...
2936
def foldLeft[B](z: B)(op: (B, A) => B): B
37+
...
3038
```
3139

32-
`foldLeft` применяет бинарный оператор `op` к начальному значению `z` и ко всем остальным элементам коллекции слева направо. Ниже приведен пример его использования.
40+
{% endtab %}
3341

34-
Начиная с начального значения 0, `foldLeft` применяет функцию `(m, n) => m + n` к каждому элементу списка и предыдущему накопленному значению.
42+
{% endtabs %}
3543

36-
```scala mdoc:nest
44+
`foldLeft` применяет бинарный оператор `op` к начальному значению `z` и ко всем остальным элементам коллекции слева направо.
45+
Ниже приведен пример его использования.
46+
47+
Начиная с начального значения `0`, `foldLeft` применяет функцию `(m, n) => m + n` к каждому элементу списка
48+
и предыдущему накопленному значению.
49+
50+
{% tabs foldLeft_use %}
51+
52+
{% tab 'Scala 2 и 3' for=foldLeft_use %}
53+
54+
```scala mdoc
3755
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
3856
val res = numbers.foldLeft(0)((m, n) => m + n)
39-
print(res) // 55
57+
println(res) // 55
4058
```
4159

42-
Множественные списки параметров имеют избыточный синтаксис, поэтому их следует использовать экономно. Можем предложить следующие варианты для использования множественных списков (каррирования):
60+
{% endtab %}
4361

44-
#### Отдельный функциональный параметр
45-
Функцию `op` можно выделить в отдельный функциональный параметр у `foldLeft`, благодаря такому выделению становится возможен более элегантный стиль передачи анонимной функции в метод. Без такого выделения код выглядел бы следующим образом:
46-
```scala
47-
numbers.foldLeft(0, {(m: Int, n: Int) => m + n})
62+
{% endtabs %}
63+
64+
### Варианты для использования
65+
66+
Предлагаемые варианты для использования множественных списков параметров включают:
67+
68+
#### Вывод типа
69+
70+
Исторически сложилось, что в Scala вывод типов происходит по одному списку параметров за раз.
71+
Скажем, у вас есть следующий метод:
72+
73+
{% tabs foldLeft1_definition %}
74+
75+
{% tab 'Scala 2 и 3' for=foldLeft1_definition %}
76+
77+
```scala mdoc
78+
def foldLeft1[A, B](as: List[A], b0: B, op: (B, A) => B) = ???
79+
```
80+
81+
{% endtab %}
82+
83+
{% endtabs %}
84+
85+
Затем при желании вызвать его следующим образом, можно обнаружить, что метод не компилируется:
86+
87+
{% tabs foldLeft1_wrong_use %}
88+
89+
{% tab 'Scala 2 и 3' for=foldLeft1_wrong_use %}
90+
91+
```scala mdoc:fail
92+
def notPossible = foldLeft1(numbers, 0, _ + _)
4893
```
49-
50-
Обратите внимание, что использование отдельного функционального параметра позволяет нам использовать автоматическое выведение типа для него, что делает код еще более кратким, это было бы невозможно без каррирования.
51-
94+
95+
{% endtab %}
96+
97+
{% endtabs %}
98+
99+
вам нужно будет вызвать его одним из следующих способов:
100+
101+
{% tabs foldLeft1_good_use %}
102+
103+
{% tab 'Scala 2 и 3' for=foldLeft1_good_use %}
104+
52105
```scala mdoc
53-
numbers.foldLeft(0)(_ + _)
106+
def firstWay = foldLeft1[Int, Int](numbers, 0, _ + _)
107+
def secondWay = foldLeft1(numbers, 0, (a: Int, b: Int) => a + b)
54108
```
55-
Если в утверждении `numbers.foldLeft(0)(_ + _)` зафиксировать отдельный параметр `z`, мы получим частично определенную функцию, которую можно переиспользовать, как показано ниже:
56-
```scala mdoc:nest
57-
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
58-
val numberFunc = numbers.foldLeft(List[Int]())_ // z = Empty.List[Int]
59109

60-
val squares = numberFunc((xs, x) => xs:+ x*x)
61-
print(squares.toString()) // List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
110+
{% endtab %}
111+
112+
{% endtabs %}
113+
114+
Это связано с тем, что Scala не может вывести тип функции `_ + _`, так как она все еще выводит `A` и `B`.
115+
Путем перемещения параметра `op` в собственный список параметров, `A` и `B` выводятся в первом списке.
116+
Затем эти предполагаемые типы будут доступны для второго списка параметров
117+
и `_ + _` станет соответствовать предполагаемому типу `(Int, Int) => Int`.
118+
119+
{% tabs foldLeft2_definition_and_use %}
62120

63-
val cubes = numberFunc((xs, x) => xs:+ x*x*x)
64-
print(cubes.toString()) // List(1, 8, 27, 64, 125, 216, 343, 512, 729, 1000)
121+
{% tab 'Scala 2 и 3' for=foldLeft2_definition_and_use %}
122+
123+
```scala mdoc
124+
def foldLeft2[A, B](as: List[A], b0: B)(op: (B, A) => B) = ???
125+
def possible = foldLeft2(numbers, 0)(_ + _)
65126
```
66127

67-
`foldLeft` и `foldRight` может быть использован в любой из следующих вариаций,
128+
{% endtab %}
129+
130+
{% endtabs %}
131+
132+
Последнее определение метода не нуждается в подсказках типа и может вывести все типы своих параметров.
133+
134+
#### Неявные параметры
135+
136+
Чтоб указать что параметр используется [_неявно_ (_implicit_)](/ru/tour/implicit-parameters.html)
137+
необходимо задавать несколько списков параметров.
138+
Примером может служить следующее:
139+
140+
{% tabs execute_definition class=tabs-scala-version %}
141+
142+
{% tab 'Scala 2' for=execute_definition %}
143+
144+
```scala mdoc
145+
def execute(arg: Int)(implicit ec: scala.concurrent.ExecutionContext) = ???
146+
```
147+
148+
{% endtab %}
149+
150+
{% tab 'Scala 3' for=execute_definition %}
151+
152+
```scala
153+
def execute(arg: Int)(using ec: scala.concurrent.ExecutionContext) = ???
154+
```
155+
156+
{% endtab %}
157+
158+
{% endtabs %}
159+
160+
#### Частичное применение
161+
162+
Методы могут объявляться с несколькими списками параметров.
163+
При этом когда такой метод вызывается с меньшим количеством списков параметров,
164+
это приводит к созданию новой функции,
165+
которая ожидает на вход недостающий список параметров.
166+
Формально это называется [частичное применение](https://ru.wikipedia.org/wiki/%D0%A7%D0%B0%D1%81%D1%82%D0%B8%D1%87%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5).
167+
168+
Например,
169+
170+
{% tabs foldLeft_partial %}
171+
172+
{% tab 'Scala 2 и 3' for=foldLeft_partial %}
173+
68174
```scala mdoc:nest
69175
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
176+
val numberFunc = numbers.foldLeft(List[Int]()) _
70177

71-
numbers.foldLeft(0)((sum, item) => sum + item) // Общая Форма
72-
numbers.foldRight(0)((sum, item) => sum + item) // Общая Форма
178+
val squares = numberFunc((xs, x) => xs :+ x*x)
179+
println(squares) // List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
73180

74-
numbers.foldLeft(0)(_+_) // Форма с каррированием
75-
numbers.foldRight(0)(_+_) // Форма с каррированием
181+
val cubes = numberFunc((xs, x) => xs :+ x*x*x)
182+
println(cubes) // List(1, 8, 27, 64, 125, 216, 343, 512, 729, 1000)
76183
```
77184

78-
79-
#### Неявные параметры
80-
Чтоб указать что параметр используется неявно (`implicit`) необходимо задавать несколько списков параметров. Примером может служить следующее:
185+
{% endtab %}
81186

82-
```scala
83-
def execute(arg: Int)(implicit ec: ExecutionContext) = ???
187+
{% endtabs %}
188+
189+
### Сравнение с «каррированием»
190+
191+
Иногда можно встретить, что метод с несколькими списками параметров называется «каррированный».
192+
193+
Как говорится [в статье на Википедии о каррировании](https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D1%80%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5),
194+
195+
> Каррирование — преобразование функции от многих аргументов в набор вложенных функций,
196+
> каждая из которых является функцией от одного аргумента.
197+
198+
Мы не рекомендуем использовать слово «каррирование» в отношении множественных списков параметров Scala по двум причинам:
199+
200+
1. В Scala множественные параметры и множественные списки параметров задаются
201+
и реализуются непосредственно как часть языка, а не преобразуются из функций с одним параметром.
202+
203+
2. Существует опасность путаницы с методами из стандартной Scala библиотеки
204+
[`curried`](<https://www.scala-lang.org/api/current/scala/Function2.html#curried:T1=%3E(T2=%3ER)>)
205+
и [`uncurried`](<https://www.scala-lang.org/api/current/scala/Function$.html#uncurried[T1,T2,R](f:T1=%3E(T2=%3ER)):(T1,T2)=%3ER>),
206+
которые вообще не включают множественные списки параметров.
207+
208+
Тем не менее, несомненно, есть сходство между множественными списками параметров и каррированием.
209+
Хотя они различаются в месте определения,
210+
в месте вызова могут тем не менее выглядеть одинаково, как в этом примере:
211+
212+
{% tabs about_currying %}
213+
214+
{% tab 'Scala 2 и 3' for=about_currying %}
215+
216+
```scala mdoc
217+
// версия с множественными списками параметров
218+
def addMultiple(n1: Int)(n2: Int) = n1 + n2
219+
// два различных способа получить каррированную версию
220+
def add(n1: Int, n2: Int) = n1 + n2
221+
val addCurried1 = (add _).curried
222+
val addCurried2 = (n1: Int) => (n2: Int) => n1 + n2
223+
// независимо от определения, вызов всех трех идентичен
224+
addMultiple(3)(4) // 7
225+
addCurried1(3)(4) // 7
226+
addCurried2(3)(4) // 7
84227
```
228+
229+
{% endtab %}
230+
231+
{% endtabs %}

0 commit comments

Comments
 (0)