Próbuję zapisać twierdzenie z tytułu jako kod w Scali. Na razie wyszło mi coś takiego:
import scala.language.higherKinds
object MonadIsMonoid {
trait Monoid[A] {
def op(a1: A, a2: A): A
def zero: A
}
trait Monad[F[_]] {
def compose[A, B, C](f: A => F[A])(g: B => F[C]): A => F[C]
def unit[A](a: => A): F[A]
}
def monadToMonoid[A, F[_]](monad: Monad[F]) = new Monoid[A => F[A]] {
override def op(a1: A => F[A], a2: A => F[A]) =
monad.compose(a1)(a2)
override val zero = (a: A) => monad.unit(a)
}
}
Próba zapisania twierdzenia to metoda monadToMonoid
. Jak widać, wrzuciłem tam parametr generyczny A
by mi się kompilowało. Skutek jest taki, że przy użyciu monoidu wyprowadzonego z monady typ w monadzie musi być zawsze taki sam, np zawsze musi być Option[Int]. Nie da się złożyć dwóch funkcji z różnymi typami, np URL => Option[String]
i String => Option[Int]
mimo, iż z użyciem monady bezpośrednio się da.
Możliwości są dwie:
- twierdzenie z tytułu posta jest nieprecyzyjne (czyli ściślej rzecz biorąc: fałszywe),
- coś przeoczyłem i jednak da się stworzyć monoid nie tracąc elastyczności monady,