如果函数评估为MonadFix
,则MaybeT
的{{1}} transformers implementation会失败。为什么Nothing
不会在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
如上所述实现了in the same way。
答案 0 :(得分:2)
我认为问题只是error
消息具有误导性。我们只关注MonadFix Maybe
。 mfix
的论证可以是四件事之一。
输入可以是严格的:f _|_ = _|_
或“f
需要评估其输入,以确定它是否会返回Nothing
或Just
”< / p>
\x -> if x then Nothing else Just True
\x -> x `seq` Nothing
\x -> x `seq` Just x
可以是const Nothing
。
可能Just . f
f
不严格。
Just . (1:)
可能Just . f
f
严格。
Just
如果函数是严格的,那么整个事情就会在无限循环中爆炸(就像fix
一样),并且看不到错误,因为我们不知道我们是否会有{{{ 1}}或Nothing
。如果它是Just
,则该函数实际上从未尝试评估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
的{{1}}而不是[]
引起。同样,我不相信触发MonadFix
是可能的,因为在确定结果为MaybeT
之后,函数必须强制参数。
答案 1 :(得分:2)
bomb
的定义在引用的库定义中确实非常混乱,尽管函数本身已正确实现。通过单调性,满足f
的任何函数f undefined = Nothing
必须等于const Nothing
。因此,定点计算将简单地产生包含在变换器堆栈中的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中还有一个证明,表明只要基础ErrT m
是有效的值递归运算符,这是mfixM
的有效值递归运算符m
。