我刚刚在haskell-cafe上问了这个问题,但我想我也可以在这里问一下。以下Backwards m的Monad实例是否有效?
{-# Language RecursiveDo #-}
import Control.Applicative.Backwards
import Control.Monad.Fix
instance MonadFix m => Monad (Backwards m) where
m >>= f = Backwards $
do
fin <- forwards (f int)
int <- forwards m
pure fin如果是这样的话,我还可以加上这个吗?
instance MonadFix m => MonadFix (Backwards m) where
mfix f = Backwards $ mfix (forwards . f)发布于 2015-12-16 05:54:00
不,它是无效的;单子定律充其量是以某种近似的方式成立的。正如Petr Pudlák's answer所显示的那样,当Backwards m >>= f的参数很严格时,f的行为并不是很好。
根据单元律,
pure () >>= (\() -> m) = m但在这个例子中,如果我没记错的话,
pure () >>= (\() -> m) = Backwards $ do
fin <- forwards (int `seq` m)
int <- pure ()
pure fin
= Backwards $ fmap fst $ mfix $ \ ~(_, int) -> do
fin <- forwards (int `seq` m)
pure (fin, ())如果底层的monad是“严格的”(即,它的>>=在其左操作数中是严格的),这将会发散。
发布于 2015-12-16 05:13:40
对于这个f,需要是惰性的,也就是说,效果不能依赖于参数。docs说
mfix f只执行一次动作f,最终的输出作为输入反馈。因此,f不应该是严格的,因为那样mfix f就会发散。
Buf如果在本例中为f,m >>= f将是严格的,那么传递给mfix的块也将是严格的。
让我们考虑一个实际的例子,其中m是readLine >>= putStrLn。颠倒顺序将意味着“打印数据,然后读取它”。除非>>=背后的函数的效果不依赖于输入,否则情况会有所不同。
https://stackoverflow.com/questions/34298726
复制相似问题