Kısa cevap
case class Behavior[S](step: S => Behavior[S])
Uzun cevap (kısa versiyon)
Terminal F-Kömürgebraları oldukça havalı.
Uzun cevap
Uyarı: dikenli tel & co sürü muz falan...
Tamam, öyleyse, bir işlev kavramına sahip olduğunuzu varsayalım F
bu, davranışınızın "bir şeyler yapmasının"ne anlama geldiğini yakalar. Çoğu kütüphanede böyle bir şey var:
trait Functor[F[_]]:
def map[A, B](fa: F[A])(f: A => B): F[B]
Bir F
- kömür cebri A
aslında sadece bir işlevdir A
-e doğru F[A]
:
trait FCoalg[F[_]: Functor, A]:
def apply(a: A): F[A]
Şimdi, bir terminal F
- kömür cebri T
bu bir F
-ek olarak her diğerinden bir özelliğe sahip olan coalgebra F
- kömür cebri A
aracılık eden bir morfizm var A => T
(böylece her şey işe gider, falan filan):
trait TerminalFCoalg[F[_]: Functor, T] extends FCoalg[F, T]:
def mediate[A](coalg: FCoalg[F, A]): A => T
Keyfi olarak uygulayabilir miyiz F
? Anlaşılıyor ki :
case class TerminalFCoalgCarrier[F[_]: Functor](
step: () => F[TerminalFCoalgCarrier[F]]
)
given tfcImpl[F[_]: Functor]: TerminalFCoalg[F, TerminalFCoalgCarrier[F]] with
def apply(a: TerminalFCoalgCarrier[F]): F[TerminalFCoalgCarrier[F]] = a.step()
def mediate[A](coalg: FCoalg[F, A]): A => TerminalFCoalgCarrier[F] = a =>
TerminalFCoalgCarrier(() => summon[Functor[F]].map(coalg(a))(mediate(coalg)))
Somut bir örnek uğruna, bu mekanizmanın akla gelebilecek en basit işlev için ne yaptığını görelim Option
:
given Functor[Option] with
def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
type ConaturalNumber = TerminalFCoalgCarrier[Option]
Terminalin olduğu ortaya çıktı F
- coalgebra için Option
bunlar sözde doğal sayılardır. Bunlar temel olarak doğal sayılardır, artı sayılabilir sonsuzluktur. Bu şeyler, potansiyel olarak sonsuz "tıklama" işlemlerinin uzunluklarını temsil etmek için oldukça uygundur.
Sonlu bir davranış üzerinde deneyelim:
enum WelshCounting:
case Eeny
case Meeny
case Miny
case Moe
object WelshCountingOptionCoalg extends FCoalg[Option, WelshCounting]:
def apply(w: WelshCounting): Option[WelshCounting] =
import WelshCounting._
w match
case Eeny => None
case Meeny => Some(Eeny)
case Miny => Some(Meeny)
case Moe => Some(Miny)
val welshMediatingMorphism =
summon[TerminalFCoalg[Option, TerminalFCoalgCarrier[Option]]]
.mediate(WelshCountingOptionCoalg)
Şimdi, yukarıdaki makineler bize otomatik olarak bu sayım kelimelerini doğal sayılara çevirmenin evrensel bir yolunu sunuyor. Doğal sayıları tanımlamak için yardımcı bir yöntem ekleyelim (yaklaşık olarak):
def describe(c: ConaturalNumber): String =
var counter = 0
var curr = c
while true do
curr.step() match
case None => return s"${counter}"
case Some(next) =>
if counter > 42 then
return "probably infinite"
else {
counter += 1
curr = next
}
throw new Error("We have counted to infinity, yay! :D")
Galce kelimeleri saymak için ne gösteriyor?
@main def demo(): Unit =
for w <- WelshCounting.values do
val conat = welshMediatingMorphism(w)
println(s"${w} -> ${describe(conat)}")
// Eeny -> 0
// Meeny -> 1
// Miny -> 2
// Moe -> 3
Tamam, bu çok düzgün. Kendisinin ardılı olan tek bir durumla sonsuz bir tıklama işlemini deneyelim:
object LoopForever extends FCoalg[Option, Unit]:
def apply(u: Unit) = Some(())
val loopForeverMediatingMorphism =
summon[TerminalFCoalg[Option, TerminalFCoalgCarrier[Option]]]
.mediate(LoopForever)
Şimdi tek devleti nasıl tarif ederdi ()
?
println(s"${()} -> ${describe(loopForeverMediatingMorphism(()))}")
// () -> probably infinite
İş gibi görünüyor.
Tam kod:
trait Functor[F[_]]:
def map[A, B](fa: F[A])(f: A => B): F[B]
trait FCoalg[F[_]: Functor, A]:
def apply(a: A): F[A]
trait TerminalFCoalg[F[_]: Functor, T] extends FCoalg[F, T]:
def mediate[A](coalg: FCoalg[F, A]): A => T
case class TerminalFCoalgCarrier[F[_]: Functor](
step: () => F[TerminalFCoalgCarrier[F]]
)
given tfcImpl[F[_]: Functor]: TerminalFCoalg[F, TerminalFCoalgCarrier[F]] with
def apply(a: TerminalFCoalgCarrier[F]): F[TerminalFCoalgCarrier[F]] = a.step()
def mediate[A](coalg: FCoalg[F, A]): A => TerminalFCoalgCarrier[F] = a =>
TerminalFCoalgCarrier(() => summon[Functor[F]].map(coalg(a))(mediate(coalg)))
given Functor[Option] with
def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
type ConaturalNumber = TerminalFCoalgCarrier[Option]
def describe(c: ConaturalNumber): String =
var counter = 0
var curr = c
while true do
curr.step() match
case None => return s"${counter}"
case Some(next) =>
if counter > 42 then
return "probably infinite"
else {
counter += 1
curr = next
}
throw new Error("We cannot count to infinity :(")
enum WelshCounting:
case Eeny
case Meeny
case Miny
case Moe
object WelshCountingOptionCoalg extends FCoalg[Option, WelshCounting]:
def apply(w: WelshCounting): Option[WelshCounting] =
import WelshCounting._
w match
case Eeny => None
case Meeny => Some(Eeny)
case Miny => Some(Meeny)
case Moe => Some(Miny)
val welshMediatingMorphism =
summon[TerminalFCoalg[Option, TerminalFCoalgCarrier[Option]]]
.mediate(WelshCountingOptionCoalg)
object LoopForever extends FCoalg[Option, Unit]:
def apply(u: Unit) = Some(())
val loopForeverMediatingMorphism =
summon[TerminalFCoalg[Option, TerminalFCoalgCarrier[Option]]]
.mediate(LoopForever)
@main def demo(): Unit =
for w <- WelshCounting.values do
val conat = welshMediatingMorphism(w)
println(s"${w} -> ${describe(conat)}")
println(s"${()} -> ${describe(loopForeverMediatingMorphism(()))}")