下面是相互递归函数对的两个示例。第一个示例终止并产生预期的结果。第二个例子类似,除了它使用了 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.
这是另外两个例子。再一次,第一个示例以预期的结果终止,而第二个示例(使用 Maybe monad)没有终止。
fun1'' = fun2'' : [1]
fun2'' = (head . tail $ fun1'') + 1
-- terminates. result is [2,1]
fun1''' = do a <- Just [1]
b <- fun2'''
return $ b : a
fun2''' = do x <- fun1'''
return $ (head . tail $ x) + 1
-- does not terminate.
我相信我的情况在语义上与我真实代码中的最后一个示例相似。我有什么办法让它终止?我会被迫放弃 Maybe monad 吗?
更新 这是我最终使用的解决方案;
fun1'''' = do a <- Just [1]
b <- fun2''''
return $ b : a
fun2'''' = do return $ (head . tail . fromJust $ fun1'''') + 1
-- terminates :)
关键区别在于fun2''''
不再fun1''''
使用绑定运算符进行操作。相反,它明确使用 fromJust (并假设fun1''''
不是Nothing
)。
在我的真实代码fun2
中实际上调用了许多其他函数。这些其他函数不会与 相互递归fun2
,并且可能会返回 Nothing 结果。幸运的是,我仍然可以在 do 表示法中隐式使用绑定运算符来访问其他必需的值。