避免使用mfix进行无限递归

时间:2020-10-18 11:17:49

标签: haskell recursion

让:

{-# LANGUAGE RecursiveDo #-}

test :: [a] -> Maybe Int
test []       = Just 0
test (_ : xs) = mdo
    unless (i == 0) Nothing -- 1
    i <- test xs            -- 2
    Just i

我正在寻找有关为什么致电例如test "hey"导致无限循环,并且通常会在处理mfix时如何避免这种行为。另外,有没有一种方法可以更正前面的玩具示例,而无需交换(1)和(2)的顺序?

1 个答案:

答案 0 :(得分:3)

这部分代码:

mdo unless (i == 0) Nothing
    i <- test xs
    Just i

减少对:

mfix (\i -> do unless (i == 0) Nothing
               j <- test xs
               Just j)

为了清楚起见,在i表达式中将j绑定到do的绑定后。

第一条mfix法则规定mfix f = _|_ iff f is strict。在这种情况下,f是:

\i -> do unless (i == 0) Nothing
         j <- test xs
         Just j

此功能很严格。 (如果用f调用_|_,将得到_|_。)因此,其上的mfix根据定义是_|_。替换成您的原始照片,我们得到:

test []       = Just 0
test (_ : xs) = _|_

这表示除非您传递test空列表,否则无论您传递给它什么其他输入,它都将始终存在差异。

当然,这就是理论方面。但是实际上,我不明白为什么您要进行这种递归,将递归定义的函数与monadic-value递归子部分混合在一起。除非仅仅是出于好奇,否则可能会有更好的方法来构建程序来避免此问题。但是为此,您必须共享更多有关您要真正实现的目标的信息。