Bind

Формальное определение

Bind - это Apply функтор, в котором функция может вводить новые значения и новый контекст функтора, включенный в контекст "подъемника". Эта операция называется flatMap[B](f: A => F[B]): F[B] (или её синоним - bind)

Для Bind должны соблюдаться следующие законы:

Функция flatMap позволяет нам определить операцию join[A](ffa: F[F[A]]): F[A], "схлопывающую" слои функтора. Синоним join - это flatten.

Определение в виде кода на Scala

trait Bind[F[_]] extends Apply[F]:
  extension [A](fa: F[A])
    def flatMap[B](f: A => F[B]): F[B]

    def bind[B](f: A => F[B]): F[B] = flatMap(f)

  def join[A](ffa: F[F[A]]): F[A] = flatMap(ffa)(a => a)

  override def apply[A, B](fab: F[A => B])(fa: F[A]): F[B] =
    flatMap(fab)(x => fa.map(x))

  override def apply2[A, B, C](fa: => F[A], fb: => F[B])(f: (A, B) => C): F[C] =
    flatMap(fa)(a => fb.map(b => f(a, b)))

Примеры

"Обертка"

import cats.Id

given Bind[Id] with
  extension [A](fa: Id[A])
    override def map[B](f: A => B): Id[B] =
      Id(f(fa))

    override def flatMap[B](f: A => Id[B]): Id[B] =
      f(fa)

Option

given Bind[Option] with
  extension [A](fa: Option[A])
    override def map[B](f: A => B): Option[B] =
      fa match
        case Some(a) => Some(f(a))
        case None    => None

    override def flatMap[B](f: A => Option[B]): Option[B] =
      fa match
        case Some(a) => f(a)
        case None    => None

Реализация

Реализация в ScalaZ

import scalaz.*
import Scalaz.*

3.some flatMap { x => (x + 1).some }  // Some(4)
3.some >>= { x => (x + 1).some }      // Some(4)
3.some >> 4.some                      // Some(4)
List(List(1, 2), List(3, 4)).join     // List(1, 2, 3, 4)

Ссылки: