Есть некоторые небольшие различия, которые делают их буквально не эквивалентными.В частности, FreeT
обеспечивает чередование f
и m
,
FreeT f m a = m (Either a (f (FreeT f m a) = m (Either a (f (m (...))))
-- m f m -- alternating
, тогда как Stream
допускает заикание, например, мы можем построить следующее без Step
между двумя Effect
:
Effect (return (Effect (return (Return r))))
, который должен быть эквивалентен в некотором смысле
Return r
Таким образом, мы возьмем частное Stream
по следующим уравнениям, которые сглаживаютслои Effect
:
Effect (m >>= \a -> return (Effect (k a))) = Effect (m >>= k)
Effect (return x) = x
При этом частном изоморфизмы
freeT_stream :: (Functor f, Monad m) => FreeT f m a -> Stream f m a
freeT_stream (FreeT m) = Effect (m >>= \case
Pure r -> return (Return r)
Free f -> return (Step (fmap freeT_stream f))
stream_freeT :: (Functor f, Monad m) => Stream f m a -> FreeT f m a
stream_freeT = FreeT . go where
go = \case
Step f -> return (Free (fmap stream_freeT f))
Effect m -> m >>= go
Return r -> return (Pure r)
Обратите внимание на цикл go
, чтобы сгладить несколько конструкторов Effect
.
Псевдозащищенность: (freeT_stream . stream_freeT) = id
Идем по индукции по потоку x
.Если честно, я вытаскиваю гипотезы индукции из воздуха.Есть, конечно, случаи, когда индукция не применима.Это зависит от того, что такое m
и f
, и может также быть некоторая нетривиальная настройка, чтобы гарантировать, что этот подход имеет смысл для фактор-типа.Но все еще должно быть много конкретных m
и f
, где эта схема применима.Я надеюсь, что есть некоторая категорическая интерпретация, которая переводит это псевдозащищенность во что-то значимое.
(freeT_stream . stream_freeT) x
= freeT_stream (FreeT (go x))
= Effect (go x >>= \case
Pure r -> return (Return r)
Free f -> return (Step (fmap freeT_stream f)))
Случай x = Step f
, гипотеза индукции (IH) fmap (freeT_stream . stream_freeT) f = f
:
= Effect (return (Step (fmap freeT_stream (fmap stream_freeT f))))
= Effect (return (Step f)) -- by IH
= Step f -- by quotient
Случай x = Return r
= Effect (return (Return r))
= Return r -- by quotient
Кейс x = Effect m
, гипотеза индукции m >>= (return . freeT_stream . stream_freeT)) = m
= Effect ((m >>= go) >>= \case ...)
= Effect (m >>= \x' -> go x' >>= \case ...) -- monad law
= Effect (m >>= \x' -> return (Effect (go x' >>= \case ...))) -- by quotient
= Effect (m >>= \x' -> (return . freeT_stream . stream_freeT) x') -- by the first two equations above in reverse
= Effect m -- by IH
Обратное движение влево в качестве упражнения.