下面是两个互相递归函数对的例子。第一个示例终止并产生预期的结果。第二个例子是类似的,除了它使用Maybe monad。 fun1'在被调用时不会终止。使用Maybe monad来终止相互递归函数
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''''
使用bind操作者操作。相反,它明确使用fromJust(并假定fun1''''
不是Nothing
)。
在我的真实代码fun2
实际上调用了一些其他功能。这些其他函数与fun2
不相互递归,并且可能会返回Nothing结果。幸运的是,我仍然可以在符号中隐式使用bind运算符来访问其他所需的值。
好吧,我明白你说的fun1/fun2实际上并不是相互递归的。这很有意义,因为fun1实际上并不需要使用fun2来产生结果。但是,我会认为fun1'/ fun2'可以被认为是相互递归的,因为如果没有其他的结果,它们都不会产生结果。 – knick
@knick是的,你是对的。适当更新它。 – Sibi