“x >>= f” 是否等同于 “retract (liftF x >>= liftF . f)”?
也就是说,从一个同时满足 Functor 和 Monad 的自由 Monad 构建的 Monad 实例是否与原始的 Monad 实例等效?
retract :: Monad m => Free m a -> m a
retract (Pure a) = return a
retract (Impure fx) = fx >>= retract
并且
liftF :: Functor f => f a -> Free f a
liftF fx = Impure (fmap Pure fx)
retract $ liftF x
= retract (Impure (fmap Pure x))
= (fmap Pure x) >>= retract
= (x >>= return . Pure) >>= retract
= x >>= \y -> (return $ Pure y) >>= retract
= x >>= \y -> (retract (Pure y))
= x >>= \y -> return y
= x >>= return
= x
所以你有
retract (liftF x >>= liftF . f)
= retract ((Impure (fmap Pure x)) >>= liftF . f)
= retract $ Impure $ fmap (>>= liftF . f) $ fmap Pure x
= (fmap (>>= liftF . f) $ fmap Pure x) >>= retract
= (fmap (\y -> Pure y >>= liftF . f) x) >>= retract
= (fmap (liftF . f) x) >>= retract
= (liftM (liftF . f) x) >>= retract
= (x >>= return . liftF . f) >>= retract
= x >>= (\y -> (return $ liftF $ f y >>= retract)
= x >>= (\y -> retract $ liftF $ f y)
= x >>= (\y -> retract . liftF $ f y)
= x >>= (\y -> f y)
= x >>= f
Free m a
与m a
同构,只是retract
确实证明了一个收缩。请注意,liftF
不是单子态映射(return
并没有转到return
)。在函子范畴中,Free是一个函子,但它不是单子态范畴中的单子态(尽管retract
看起来很像join
,而liftF
看起来很像return
)。 ~ : Free m a -> Free m a -> Prop
a ~ b = (retract a) ==_(m a) (retract b)
Free m a/~
。我断言该类型与m a
同构。因为(liftF (retract x)) ~ x
,由于(retract . liftF . retract $ x) ==_(m a) retract x
。因此,monad的自由monad正好是那个monad加上一些额外的数据。当m
是一个单子结构时,这与[m]
"本质上是相同的"。
data M a = M Integer a
bindUsing :: (Integer -> Integer -> Integer) -> M a -> (a -> M b) -> M b
bindUsing f (M n a) k =
let M m b = k a
in M (f m n) b
-- Any of the below instances is a valid Monad instance
instance Monad M where
return x = M 0 x
(>>=) = bindUsing (+)
instance Monad M where
return x = M 1 x
(>>=) = bindUsing (*)
Impure (a,mzero) = a
,因此 Free (Writer m) a
同构于 Writer m a
。Free (Writer m) a = Writer [m] a
,如果您关心的是单子结构,则它们看起来相似。它们不同之处在于您可以编写一个函数来区分它们,另一方面,它们相同之处在于您可能不应该这样做 :)。 - Philip JFFree m a
视为与m a
“相同”,将[m]
视为与m
“相同”。这可以很容易地通过使用商类型(在Haskell中我们只能假装存在)来形式化,并且是使用自由单子实现高效的Pipes
的基础,即使该实现不遵守变换器定律(因为lift
不是单子态射),即使你没有Haskell中使其“安全”的商类型。 - Philip JFretract
仍然使用底层的Monad
实例。Free
monads应该始终比在functor上定义的任何其他monad更大。撤回应该是使Free
成为通用的唯一映射,对吗? - J. Abrahamson
retract
后将一些等价的事物商掉,它们就是同构的。否则就只是一个收缩。你想要哪种解释取决于你正在做什么,但对于某些应用程序,你可能确实想在某个函子f
上使用Free
,但需要一个单子变换器。获得这样的变换器的明显方法是考虑Free(f :+: m)
,但这不是变换器,因为liftF
等不是单子态射。这是Pipes
的一个很好的例子。您可以将它们区分开来,因此如果您想要执行此操作,请将其包装在模块中/不导出构造函数。 - Philip JF