Начнем со списка чисел от 1 до 5 и нескольких простых функций — одна для добавления 1, другая для возведения в квадрат и третья для добавления 100.
01
02
03
04
05
06
07
08
09
10
11
|
scala> val foo = 1 to 5 toList foo : List[Int] = List( 1 , 2 , 3 , 4 , 5 ) scala> val add 1 = (x : Int) = > x + 1 add 1 : (Int) = > Int = <function 1 > scala> val add 100 = (x : Int) = > x + 100 add 100 : (Int) = > Int = <function 1 > scala> val sq = (x : Int) = > x * x sq : (Int) = > Int = <function 1 > |
Затем мы можем применить любую из этих функций к каждому элементу списка foo, используя функцию map.
1
2
3
4
5
6
7
8
|
scala> foo map add 1 res 0 : List[Int] = List( 2 , 3 , 4 , 5 , 6 ) scala> foo map add 100 res 1 : List[Int] = List( 101 , 102 , 103 , 104 , 105 ) scala> foo map sq res 2 : List[Int] = List( 1 , 4 , 9 , 16 , 25 ) |
Мы можем сохранить результаты сопоставления всех значений через add1, а затем отобразить результирующий список через sq.
1
2
3
4
5
|
scala> val bar = foo map add 1 bar : List[Int] = List( 2 , 3 , 4 , 5 , 6 ) scala> bar map sq res 3 : List[Int] = List( 4 , 9 , 16 , 25 , 36 ) |
Или, если мы не заботимся о промежуточном результате, мы можем просто продолжить отображение через обе функции.
1
2
|
scala> foo map add 1 map sq res 4 : List[Int] = List( 4 , 9 , 16 , 25 , 36 ) |
Выше мы сделали sq (add1 (x)) для каждого x в списке foo. Вместо этого мы могли бы составить две функции, так как sq (add1 (x)) = sq? Add1 (x). Вот как это выглядит в Scala:
1
2
3
4
5
|
scala> val sqComposeAdd 1 = sq compose add 1 sqComposeAdd 1 : (Int) = > Int = <function 1 > scala> foo map sqComposeAdd 1 res 5 : List[Int] = List( 4 , 9 , 16 , 25 , 36 ) |
Конечно, мы можем сделать это с более чем двумя функциями.
1
2
3
4
5
|
scala> foo map add 1 map sq map add 100 res 6 : List[Int] = List( 104 , 109 , 116 , 125 , 136 ) scala> foo map (add 100 compose sq compose add 1 ) res 7 : List[Int] = List( 104 , 109 , 116 , 125 , 136 ) |
И так далее. Теперь представьте, что вы хотите, чтобы пользователь программы, которую вы написали, мог выбирать функции, которые он хочет применить к списку элементов, возможно, из набора предопределенных функций, которые вы предоставили, и, возможно, те, которые они сами определяют. , Итак, вот действительно полезная часть: мы можем составить этот произвольный набор функций на лету, чтобы превратить их в единую функцию, без необходимости писать «составлять… составлять… составлять…» или «отображать… отображать… отображать… отображать» Сделайте это, создав список функций (в том порядке, в котором мы хотим применить их к значениям), а затем уменьшив их, используя функцию compose. Эквивалент тому, что мы имели выше:
1
2
3
4
5
|
scala> val fncs = List(add 1 , sq, add 100 ) fncs : List[(Int) = > Int] = List(<function 1 >, <function 1 >, <function 1 >) scala> foo map ( fncs.reverse reduce ( _ compose _ ) ) res 8 : List[Int] = List( 104 , 109 , 116 , 125 , 136 ) |
Обратите внимание, что для правильного упорядочения композиции необходимо было перевернуть список. Если вы не хотите этого делать, вы можете использовать andThen в Scala.
1
2
|
scala> foo map (add 1 andThen sq andThen add 100 ) res 9 : List[Int] = List( 104 , 109 , 116 , 125 , 136 ) |
Что мы, конечно, можем использовать и с помощью Reduce.
1
2
|
scala> foo map ( fncs reduce ( _ andThen _ ) ) res 10 : List[Int] = List( 104 , 109 , 116 , 125 , 136 ) |
Поскольку функции являются гражданами первого класса (то, что мы использовали несколько раз выше), мы можем присвоить составной или andThened результат значению val и использовать его напрямую.
1
2
3
4
5
|
scala> val superFunction = fncs reduce ( _ andThen _ ) superFunction : (Int) = > Int = <function 1 > scala> foo map superFunction res 11 : List[Int] = List( 104 , 109 , 116 , 125 , 136 ) |
Этот пример, конечно, является искусственным, но общий шаблон прекрасно работает с гораздо более сложными / интересными функциями и может предоставить хороший способ настройки набора альтернативных функций для различных вариантов использования.
Ссылка: весело с составлением функций в Scala от нашего партнера JCG Джейсона Болдриджа в блоге Bcomposes
Статьи по Теме :