为什么 `mfix` 在 `MaybeT` 中不完全

Why is `mfix` not total in `MaybeT`

如果函数的计算结果为 NothingMonadFixtransformers implementation for MaybeT 将失败。为什么 Nothing 没有传播到 mfix

mfix' :: MonadFix m => (a -> MaybeT m a) -> MaybeT m a
mfix' f = MaybeT $ mfix $ \case
  Nothing -> return Nothing
  Just x -> runMaybeT $ f x

一定有一个我看不到的充分理由,因为 ListT 根本没有实现 MonadFix,而 Maybe 如上所述实现了它 in the same way

我认为问题只是 error 消息具有误导性。让我们只关注 MonadFix Maybemfix 的参数可以是以下四种之一。

  1. 输入可以是严格的:f _|_ = _|_或“f需要评估其输入以决定是否returnNothingJust"

    \x -> if x then Nothing else Just True
    \x -> x `seq` Nothing
    \x -> x `seq` Just x
    
  2. 可以是const Nothing.

  3. 可以是Just . f其中f不严格

    Just . (1:)
    
  4. 可以是Just . f,其中f是严格的。

    Just
    

如果函数是严格的,那么整个事情就会在无限循环中爆炸(就像 fix),并且看不到错误,因为我们不知道我们是否会有一个NothingJust。如果它是 const Nothing,该函数实际上从未尝试计算 error,并且什么也没有发生。如果它是 Just . f 并且 f 不严格,那么它只是 Just $ fix f(根据法律:mfix $ return . f = return $ fix f)。而且,如果 f 是严格的,我们会得到 Just _|_(同样,根据法律)。请注意,我们从未看到 error 被触发。

类似的推理适用于 MonadFix (MaybeT m)。我觉得这次还是举个例子比较好:

runMaybeT $ mfix $ \x -> MaybeT $
             (x `seq` Nothing) :
             Nothing           :
             (Just (1:x))      :
             (Just x)          :
             (x `seq` [])

我上面列出的四个案例中的每一个都在该列表中。结果的第一个元素是一个无限循环。第二个是Nothing。第三个是repeat 1,第四个是Just无限循环。尝试访问超出此范围的 "elements" 会触发另一个无限循环,这次是由 []MonadFix 而不是 MaybeT 引起的。同样,我认为不可能触发 error,因为该函数必须在已经确定结果为 Nothing.

之后强制执行参数

bomb 的定义在引用的库定义中确实非常混乱,尽管函数本身已正确实现。根据单调性,任何满足 f undefined = Nothing 的函数 f 必须等于 const Nothing。因此,fixed-point 计算将简单地产生包含在转换器堆栈中的 Nothing 的正确答案。

有关详细信息,请参阅 this work 的第 4.9 节,尽管为清楚起见,原始定义省略了构造函数,并且使用名称 ErrT 代替了 MaybeT。 (那时候还没有MTL!)那里的定义是这样的:

mfixErrM :: (α → ErrT m α) → ErrT m α
mfixErrM f = mfixM (f · unErr)
     where unErr (Ok a) = a

附录 B.7 中还有一个证明表明只要基础 mfixM 是有效的 value-recursion,这就是 ErrT m 的有效 value-recursion 运算符] m.

的运算符