Compose
Формальное определение
Compose
объединяет две функции в одну.
Функция compose
позволяет реализовать Semigroup
и Plus в терминах объединения функций.
Compose
должен удовлетворять следующим законам:
- Ассоциативность:
compose(compose(f, g), h) = compose(f, compose(g, h))
Композиция
Имея стрелку f от a к b и стрелку g от b к c, их композиция представляет собой стрелку, идущую непосредственно от a к c. Другими словами, если имеются две стрелки, цель одной из которых совпадает с источником другой, то всегда можно скомпоновать их, чтобы получить третью стрелку. Обозначается как: \(h = g \circ f\)
Ассоциативность
Предположим, что удалось разложить g на \(j \circ k\). Тогда \(h = (j \circ k) \circ f\) Желательно, чтобы это разложение было таким же, как и \(h = j \circ (k \circ f)\). При этом должна существовать возможность заявить, что h была декомпозирована на три более простые функции \(h = j \circ k \circ f\) и не нужно отслеживать, какая декомпозиция была первой. Это свойство называется ассоциативностью композиции.
Определение в виде кода на Scala
trait Compose[=>:[_, _]]:
self =>
/** Ассоциативный `=>:` бинарный оператор. */
def compose[A, B, C](f: B =>: C, g: A =>: B): A =>: C
protected[arrow] trait ComposePlus extends Plus[[A] =>> A =>: A]:
def plus[A](f1: A =>: A, f2: => A =>: A): A =>: A = self.compose(f1, f2)
protected[arrow] trait ComposeSemigroup[A] extends Semigroup[A =>: A]:
def combine(f1: A =>: A, f2: A =>: A): A =>: A = self.compose(f1, f2)
def plus: Plus[[A] =>> A =>: A] = new ComposePlus {}
def semigroup[A]: Semigroup[A =>: A] = new ComposeSemigroup {}
Примеры
Функция от одной переменной
given Compose[Function1] with
override def compose[A, B, C](f: B => C, g: A => B): A => C = g andThen f
Реализация
Реализация в Cats
import cats.*, cats.data.*, cats.syntax.all.*
lazy val f = (_:Int) + 1
lazy val g = (_:Int) * 100
(f >>> g)(2)
// res0: Int = 300
(f <<< g)(2)
// res1: Int = 201
Реализация в ScalaZ
import scalaz.*
import Scalaz.*
val f1 = (_:Int) + 1
val f2 = (_:Int) * 100
(f1 >>> f2)(2) // 300
(f1 <<< f2)(2) // 201
Ссылки: