Ответ 1
Ссылка на универсальную алгебру была хорошей отправной точкой, и после прочтения ее немного все встало на свои места. Мы ищем F-алгебру:
type Alg f x = f x -> x
для любого (endo) -функтора f
. Например, для моноидной алгебры функтор имеет вид:
data MonoidF m = MEmpty | MAppend m m deriving Functor
Для любого экземпляра Monoid
существует очевидная моноидная алгебра:
monoidAlg :: Monoid m => Alg MonoidF m
monoidAlg MEmpty = mempty
monoidAlg (MAppend a b) = mappend a b
Теперь мы можем взять определение свободного функтора из пакета free-functors и заменить ограничение класса на f-алгебру:
newtype Free f a = Free { runFree :: forall b. Alg f b -> (a -> b) -> b }
Свободный функтор в некотором смысле является лучшим способом превратить любое множество a
в алгебру. Вот как это делается:
unit :: a -> Free f a
unit a = Free $ \_ k -> k a
Это лучший способ, поскольку для любого другого способа превратить a
в алгебру b
, мы можем дать функцию от свободной алгебры до b
:
rightAdjunct :: Functor f => Alg f b -> (a -> b) -> Free f a -> b
rightAdjunct alg k (Free f) = f alg k
Осталось фактически показать, что свободный функтор создает f-алгебру (и это то, о чем вы просили):
freeAlg :: Functor f => Alg f (Free f a)
freeAlg ff = Free $ \alg k -> alg (fmap (rightAdjunct alg k) ff)
Объяснить немного: ff
имеет тип f (Free f a)
, и нам нужно построить Free f a
. Мы можем сделать это, если мы сможем построить a b
, учитывая alg :: f b -> b
и k :: a -> b
. Поэтому мы можем применить alg
к ff
, если мы можем отобразить каждый Free f a
, который он содержит в b
, но то, что делает rightAdjunct
с alg
и k
.
Как вы могли догадаться, эта Free f
- это свободная монада на функторе f
(закодированная в церкви версия, чтобы быть точным.)
instance Functor f => Monad (Free f) where
return = unit
m >>= f = rightAdjunct freeAlg f m