Начнем со списка чисел от 1 до 5 и нескольких простых функций — одна для добавления 1, другая для возведения в квадрат и третья для добавления 100.
|
01
02
03
04
05
06
07
08
09
10
11
|
scala> val foo = 1 to 5 toListfoo: List[Int] = List(1, 2, 3, 4, 5)scala> val add1 = (x: Int) => x + 1add1: (Int) => Int = <function1>scala> val add100 = (x: Int) => x + 100add100: (Int) => Int = <function1>scala> val sq = (x: Int) => x * xsq: (Int) => Int = <function1> |
Затем мы можем применить любую из этих функций к каждому элементу списка foo, используя функцию map.
|
1
2
3
4
5
6
7
8
|
scala> foo map add1res0: List[Int] = List(2, 3, 4, 5, 6)scala> foo map add100res1: List[Int] = List(101, 102, 103, 104, 105)scala> foo map sqres2: List[Int] = List(1, 4, 9, 16, 25) |
Мы можем сохранить результаты сопоставления всех значений через add1, а затем отобразить результирующий список через sq.
|
1
2
3
4
5
|
scala> val bar = foo map add1bar: List[Int] = List(2, 3, 4, 5, 6)scala> bar map sqres3: List[Int] = List(4, 9, 16, 25, 36) |
Или, если мы не заботимся о промежуточном результате, мы можем просто продолжить отображение через обе функции.
|
1
2
|
scala> foo map add1 map sqres4: 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 sqComposeAdd1 = sq compose add1sqComposeAdd1: (Int) => Int = <function1>scala> foo map sqComposeAdd1res5: List[Int] = List(4, 9, 16, 25, 36) |
Конечно, мы можем сделать это с более чем двумя функциями.
|
1
2
3
4
5
|
scala> foo map add1 map sq map add100res6: List[Int] = List(104, 109, 116, 125, 136)scala> foo map (add100 compose sq compose add1)res7: List[Int] = List(104, 109, 116, 125, 136) |
И так далее. Теперь представьте, что вы хотите, чтобы пользователь программы, которую вы написали, мог выбирать функции, которые он хочет применить к списку элементов, возможно, из набора предопределенных функций, которые вы предоставили, и, возможно, те, которые они сами определяют. , Итак, вот действительно полезная часть: мы можем составить этот произвольный набор функций на лету, чтобы превратить их в единую функцию, без необходимости писать «составлять… составлять… составлять…» или «отображать… отображать… отображать… отображать» Сделайте это, создав список функций (в том порядке, в котором мы хотим применить их к значениям), а затем уменьшив их, используя функцию compose. Эквивалент тому, что мы имели выше:
|
1
2
3
4
5
|
scala> val fncs = List(add1, sq, add100)fncs: List[(Int) => Int] = List(<function1>, <function1>, <function1>)scala> foo map ( fncs.reverse reduce (_ compose _) )res8: List[Int] = List(104, 109, 116, 125, 136) |
Обратите внимание, что для правильного упорядочения композиции необходимо было перевернуть список. Если вы не хотите этого делать, вы можете использовать andThen в Scala.
|
1
2
|
scala> foo map (add1 andThen sq andThen add100)res9: List[Int] = List(104, 109, 116, 125, 136) |
Что мы, конечно, можем использовать и с помощью Reduce.
|
1
2
|
scala> foo map ( fncs reduce (_ andThen _) )res10: List[Int] = List(104, 109, 116, 125, 136) |
Поскольку функции являются гражданами первого класса (то, что мы использовали несколько раз выше), мы можем присвоить составной или andThened результат значению val и использовать его напрямую.
|
1
2
3
4
5
|
scala> val superFunction = fncs reduce (_ andThen _)superFunction: (Int) => Int = <function1>scala> foo map superFunctionres11: List[Int] = List(104, 109, 116, 125, 136) |
Этот пример, конечно, является искусственным, но общий шаблон прекрасно работает с гораздо более сложными / интересными функциями и может предоставить хороший способ настройки набора альтернативных функций для различных вариантов использования.
Ссылка: весело с составлением функций в Scala от нашего партнера JCG Джейсона Болдриджа в блоге Bcomposes
Статьи по Теме :