Haskell 使用Maybe单子终止相互递归函数

Haskell 使用Maybe单子终止相互递归函数,haskell,recursion,lazy-evaluation,maybe,Haskell,Recursion,Lazy Evaluation,Maybe,下面是两个相互递归函数对的示例。第一个示例终止并生成预期结果。第二个例子类似,只是它使用了Maybe monad。fun1'在调用时不终止 fun1 = 1 + fun2 fun2 = let x = fun1 in 2 -- terminates. result is 3. fun1' = do a <- Just 1 b <- fun2' return $ a + b fun2' = do x <- fun1

下面是两个相互递归函数对的示例。第一个示例终止并生成预期结果。第二个例子类似,只是它使用了Maybe monad。fun1'在调用时不终止

fun1 = 1 + fun2
fun2 = let x = fun1 
       in  2
-- terminates. result is 3.

fun1' = do a <- Just 1 
           b <- fun2'
           return $ a + b
fun2' = do x <- fun1'
           return 2
-- does not terminate.
fun1=1+fun2
fun2=设x=fun1
在2
--终止。结果是3。

fun1'=do a这里的问题是,您的终止函数
fun1
不是互斥的,即使它看起来是互斥的。 实际上,您的
fun2'
函数实际上只是引用
2
值。例如:

λ> let x = undefined in 2
2
未定义的
零件根本不会得到评估。因此,您的
x=fun1
将不会在
fun2
函数中计算,因此它将成功终止,因为
fun2
计算结果为
2

而在您的
fun2'
示例中,它并没有减少到任何值。所以,它不会终止。实际上,如果您实际将
fun2'
函数转换为let表达式,就像您的
fun2
示例一样,那么它将终止:

fun2' = let x = fun1'
        in (Just 2)
fun2'
是一个相互递归的函数,它引用值
2

λ> tail fun1''
[1]
λ> head $ tail fun1''
1
λ> (head $ tail fun1'') + 1
2

所以
fun2'
实际上是指一个值
2

之所以
fun1'/fun2'
不终止,是因为
可能
monad的绑定操作(
>=
)需要检查第一个参数是
还是
仅(…)
。所以当你做
x的时候,我想你别无选择,只能放弃单子

请记住,单子只表示可以链接在一起的计算序列。
Maybe
monad表示可能失败的计算,当序列中的一个计算失败时,我们最终得到一个
Nothing
。虽然最终结果似乎不需要
x
的值(因此我们预计程序会因延迟求值而停止),但它是一个序列,因此必须求值,从而产生无限递归

相反,请尝试以下方法:

fun1' = do a <- Just 1 
           b <- fun2'
           return $ a + b
fun2' = do Nothing
           fun1'
           return 2
main = print $ fun1'

fun1'=do a如果需要将
Maybe
monad与相互递归相结合,那么您可能需要,这允许
mdo
块内的一元计算值相互递归引用(对于支持
MonadFix
类的monad)。下面编译并给出了您可能期望的结果
([2,1],2)

{-# LANGUAGE RecursiveDo #-}

maybeFuns = mdo
    fun1''' <- do a <- Just [1]
                  return $ fun2''' : a              
    fun2''' <- return $ (head . tail $ fun1''') + 1
    return (fun1''', fun2''')
{-#语言递归DO}
maybeFuns=mdo

fun1''好的,我明白你所说的fun1/fun2实际上不是相互递归的。这是有道理的,因为fun1实际上不需要使用fun2来生成其结果。但是,我认为fun1'/fun2''可以被认为是相互递归的,因为没有另一个,任何一个都不能产生其结果。@knick是的,你是对的。适当地更新了它。
fun1' = do a <- Just 1 
           b <- fun2'
           return $ a + b
fun2' = do Nothing
           fun1'
           return 2
main = print $ fun1'
{-# LANGUAGE RecursiveDo #-}

maybeFuns = mdo
    fun1''' <- do a <- Just [1]
                  return $ fun2''' : a              
    fun2''' <- return $ (head . tail $ fun1''') + 1
    return (fun1''', fun2''')