如果我们用它来写下mfix,那么对于Functor实例,liftM是否太严格?

问题描述

fmap的{​​{1}}通常认为liftM

Monads

但是,正如人们所看到的,它使用绑定(因为右手将liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r liftM f m1 = do { x1 <- m1; return (f x1) } 减掉)。我想知道这样的m1 >>= \ x1 -> return (f x1)是否可以用于写下fmap的单子,这些单子具有严格的mfix运算符。更确切地说,我想知道以下使用>>=again)的实现。

我使用的monad是Control.Arrow.loop,但是无论何时Identity进行绑定时,它都会强制执行其中的任何内容

seq

我的直觉是是的,可以使用。我认为只有两种情况会遇到问题:

  1. 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
  2. 我们将myMfix / mfix应用于myMfix

这两种情况都非常简单,我们首先不会期望任何收敛的结果。我认为,其他情况可能会被迫 WHNF 而不会强迫反馈。

我的直觉正确吗?如果没有,可以举一个失败的例子吗?

解决方法

您对Id'的定义不是有效的monad,因为它不符合左单位定律:

  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的{​​{1}}的定义是否有效的讨论尚无定论,更不用说通过Kleisli构造进行的定义是否忠实了。

已经说过,如果要查看定义是否是Id'的忠实实现,则需要写下并证明严格性,纯净性和左收缩的三个定律。如果您从一个实际的单子反馈开始(而不是您的mfix未能通过该测试),那么您需要建立这三个定律才能被视为有效的单子反馈运算符。如果不做这项工作,就不可能说出定义是如何概括的。

我的直觉是,您通过Kleisli构造的直觉可能非常适合行为良好的箭头,即Id'运算符确实满足右紧定律的那些箭头。但是,众所周知,具有左约束绑定操作符的单子的Kleisli类别上的箭头没有loop个满足右紧缩操作符的操作符。 (请参见Corollary 3.1.7和第6.4.1节中的讨论。)

因此,任何具有左严格绑定运算符(例如loop[]Maybe,严格状态等)的monad都将通过测试。但是,由诸如环境,懒惰状态之类的单子产生的箭头,以及那些由类单元(又称为作家单子)构建的箭头,可能会奏效。