fmap for Monads通常默认为liftM
liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r
liftM f m1 = do { x1 <- m1; return (f x1) }然而,正如人们所看到的,它使用绑定(作为m1 >>= \ x1 -> return (f x1)中的右手去糖块)。我想知道这样的fmap是否可以用于为具有严格的>>=运算符的monads写下mfix。更准确地说,我想知道下面使用Control.Arrow.loop (再一次)实现的情况。
我使用的monad是Identity,但是每当使用seq绑定时,它就会强制使用它内部的任何内容。
newtype Id' a = Id' { runId' :: a } deriving ...
instance Functor Id' where
fmap = liftM -- instead of `f <$> (Id' x) = Id' (f x)`.
instance Applicative Id' where
pure = return
(<*>) = ap
instance Monad Id' where
return = Id'
(Id' x) >>= k = x `seq` k x
instance MonadFix Id' where
mfix f = let a = f (runId' a) in a
myMfix :: MonadFix m => (a -> m a) -> m a
myMfix k = let f ~(_, d) = ((,) d) <$> k d
in (flip runKleisli () . loop . Kleisli) f我的直觉是是的,可以用。我估计我们只在两种情况下遇到问题:
k我们应用mfix/myMfix是严格的。mfix/myMfix应用于return。这两种情况都相当简单,我们一开始不期望有任何收敛的结果。我认为其他病例可以强迫WHNF而不强制反馈。
我的直觉正确吗?如果没有,能否给出一个失败的例子?
发布于 2020-08-26 12:43:36
您对Id'的定义不是有效的单体,因为它不符合左单元定律:
return undefined >= const (return 3)
= Id' undefined >>= const (return 3)
= undefined `seq` const (return 3) undefined
= undefined这并不等于
const (return 3) undefined
= return 3
= Id' 3因此,关于MonadFix for Id'的定义是否有效的讨论是毫无意义的,更不用说通过Kleisli构造的定义是否可靠。
话虽如此,如果您想要查看定义是否是mfix的忠实实现,则需要记录并证明严格、纯洁和左缩的三条定律。如果您从一个实际的monad开始(而不是您的Id'没有通过测试),那么您需要建立这三个定律,才能被认为是一个有效的一元反馈操作符。如果不做这项工作,就不可能知道定义是如何泛化的。
我的直觉是,你通过Kleisli构造定义的直觉很可能支持行为良好的箭头,也就是那些其loop算子确实满足正确的紧缩定律的箭头。然而,众所周知,具有左严格绑定运算符的monad的Kleisli类别上的箭头不具有满足右紧性的loop算子。(请参阅推论3.1.7和第6.4.1节中的讨论。)
因此,任何具有左严格绑定运算符(如[]、Maybe、IO、严格状态等)的monad。将无法通过测试。但是从环境,懒惰状态,以及那些由单子植物建造出来的单子植物中产生的箭头。作家单子)也许能解决问题。
https://stackoverflow.com/questions/63578343
复制相似问题