Bi-Monad
Формальное определение
Bimonad
напрямую расширяет Monad и Comonad без введения новых методов.
Bimonad
отличается от других классов типов Bi,
таких как Bifunctor, Bifoldable
или Bitraverse, где префикс описывает F[_, _]
.
Bimonad
— это F[_]
, а префикс Bi здесь имеет другое значение: это и монада, и комонада.
Имейте в виду, что бимонада имеет свои собственные дополнительные законы,
поэтому то, что является одновременно монадическим и комонадным, необязательно может быть законной бимонадой.
Определение в виде кода на Scala
trait Bimonad[F[_]] extends Monad[F], CoMonad[F]
Примеры
Непустой список
given Bimonad[NonEmptyList] with
def unit[A](a: => A): NonEmptyList[A] = NonEmptyList(a, List.empty)
def coUnit[A](fa: NonEmptyList[A]): A = fa.head
extension [A](fa: NonEmptyList[A])
def flatMap[B](f: A => NonEmptyList[B]): NonEmptyList[B] =
fa match
case NonEmptyList(head, Nil) => f(head)
case NonEmptyList(head, h :: tail) =>
f(head) ++ NonEmptyList(h, tail).flatMap(f)
def cobind[B](f: NonEmptyList[A] => B): NonEmptyList[B] =
NonEmptyList(f(fa), Nil)
Реализация
Реализация в Cats
import cats.*
import cats.data.*
import cats.syntax.all.*
def make[T[_]: Bimonad](config: T[String]): String =
config
.flatMap(c => Bimonad[T].pure(c + " with option A"))
.flatMap(c => Bimonad[T].pure(c + " with option B"))
.flatMap(c => Bimonad[T].pure(c + " with option C"))
.extract
make(NonEmptyList.one("config"))
// res0: String = "config with option A with option B with option C"
Ссылки: