Bezpłatne foo okazuje się najprostszą rzeczą, która spełnia wszystkie prawa „foo”. To znaczy, że spełnia dokładnie prawa niezbędne do bycia foo i nic więcej.
Zapominający funktor to taki, który „zapomina” część struktury, przechodząc z jednej kategorii do drugiej.
Biorąc pod uwagę funktory F : D -> C
, i G : C -> D
, jak mówimy F -| G
, F
jest on przyległy do G
, lub G
jest przyległy do, F
ilekroć forall a, b: F a -> b
jest izomorficzny a -> G b
, gdzie strzałki pochodzą z odpowiednich kategorii.
Formalnie wolny funktor pozostaje przyległy do zapomnianego funktora.
Wolny Monoid
Zacznijmy od prostszego przykładu, wolnej monoidy.
Weź monoid, który jest zdefiniowany przez jakiś zestaw nośnej T
, funkcja binarna mash parę elementów ze sobą f :: T → T → T
, a także unit :: T
takie, które mają prawo zrzeszania się, prawo oraz tożsamości: f(unit,x) = x = f(x,unit)
.
Możesz zrobić funktor U
z kategorii monoidów (gdzie strzałki są homomorfizmami monoidów, tzn. Zapewniają, że odwzorowują unit
się unit
na innym monoidie, i że możesz komponować przed lub po mapowaniu na drugą monoidę bez zmiany znaczenia) do kategorii zestawów (gdzie strzałki są tylko strzałkami funkcyjnymi), które „zapominają” o operacji unit
i po prostu dają ci zestaw nośny.
Następnie możesz zdefiniować funktor F
z kategorii zestawów z powrotem do kategorii monoidów, która pozostaje przyległa do tego funktora. Ten funktor jest funktorem, który odwzorowuje zbiór a
na monoid [a]
, gdzie unit = []
i mappend = (++)
.
Aby przejrzeć nasz dotychczasowy przykład w pseudo-Haskell:
U : Mon → Set -- is our forgetful functor
U (a,mappend,mempty) = a
F : Set → Mon -- is our free functor
F a = ([a],(++),[])
Następnie pokazanie F
jest bezpłatne, musimy wykazać, że jest on sąsiadujący z U
zapomnianym funktorem, to znaczy, jak wspomniano powyżej, musimy pokazać, że
F a → b
jest izomorficzny a → U b
pamiętajcie teraz, że cel F
jest w kategorii Mon
monoidów, gdzie strzały są homomorfizmami monoidów, więc musimy pokazać, że homomorfizm monoidów z [a] → b
można dokładnie opisać funkcją a → b
.
W Haskell nazywamy stronę tego, w której żyjemy Set
(er, Hask
kategoria typów Haskell, którą udajemy, jest ustawiona), właśnie foldMap
, która, gdy specjalizujemy Data.Foldable
się w Listach, ma typ Monoid m => (a → m) → [a] → m
.
Istnieją konsekwencje wynikające z tego, że jest to dodatek. Zwłaszcza, że jeśli zapomnisz, a następnie zbuduj za darmo, to zapomnij jeszcze raz, tak jak raz zapomniałeś, a my możemy to wykorzystać do zbudowania połączenia monadycznego. ponieważ UFUF
~ U(FUF)
~ UF
, i możemy przekazać tożsamość monomorfizmu monoidu od [a]
do [a]
poprzez izomorfizm, który określa nasze przyleganie, uzyskajmy, że izomorfizm listy od [a] → [a]
jest funkcją typu a -> [a]
, a to jest po prostu powrót do list.
Możesz to wszystko skomponować bardziej bezpośrednio, opisując listę w tych kategoriach za pomocą:
newtype List a = List (forall b. Monoid b => (a -> b) -> b)
Wolna monada
Czym jest wolna monada ?
Cóż, robimy to samo, co poprzednio, zaczynamy od zapomnianego funktora U z kategorii monad, w których strzały są homomorfizmami monad, do kategorii endofunkcji, w których strzały są naturalnymi transformacjami, i szukamy funktora, który jest pozostawiony obok siebie do tego.
Jak to się ma do pojęcia wolnej monady, jak się zwykle używa?
Wiedząc, że coś jest wolną monadą, Free f
mówi ci, że nadanie monomorfizmowi monady z Free f -> m
, jest tym samym (izomorficznym), co nadanie naturalnej transformacji (homomorfizm funktorski) f -> m
. Pamiętaj, że F a -> b
musi być izomorficzny, aby a -> U b
F pozostawał przyległy do U. U tutaj mapowane monady na funktory.
F jest co najmniej izomorficzny do Free
typu używanego w moim free
pakiecie podczas włamań.
Możemy również skonstruować go w ścisłej analogii do powyższego kodu dla wolnej listy, definiując
class Algebra f x where
phi :: f x -> x
newtype Free f a = Free (forall x. Algebra f x => (a -> x) -> x)
Cofree Comonady
Możemy skonstruować coś podobnego, patrząc na właściwe połączenie z zapomnianym funktorem, zakładając, że istnieje. Funktor Cofree jest po prostu / właściwie przylegający / do zapomnianego funktora, a symetria, wiedząc, że coś jest cofree comonad, jest tym samym, co wiedza, że nadanie homomorfizmu comonad z w -> Cofree f
jest tym samym, co danie naturalnej transformacji w -> f
.