任何人都可以帮我理解这段代码
solve s | s == 0 = Nothing
| s == 1 = Just 1
| otherwise =
check [solve (s-(x*2)) | x <- [1..9]]
check x = case x of
[] -> Nothing
(Nothing:xs) -> check xs
(x:xs) -> x
为什么当我尝试使用偶数值运行它时,这会给堆栈溢出流量,并且在haskell中有什么方法我可以调试并查看正在运行的程序的实际值,就像我们在eclipse中那样?
感谢
答案 0 :(得分:9)
至少对于GHCi,没有办法“逐步”完成代码(编辑:不再如此,请参阅下面的评论),但您当然可以使用Debug.Trace添加调试语句。换句话说,如果您想检查solve
的所有递归调用,您可以说:
check [trace ("solving for " ++ show (s-(x*2)))) (solve (s-(x*2))) | x <- [1..9]]
有更简洁的方法可以写出来,但这只是说明了这个想法。
在这种特殊情况下,无限递归的原因是永远不会达到解决的基本情况。例如solve 2
,解析为check [solve 0, solve -2, solve -4 ..., solve -16]
,solve -2
解析为check [solve -4, solve -6, ...]
等。
答案 1 :(得分:2)
堆栈溢出表明无限递归。在“解决”的情况下分支 不保证会终止。我不确定代码应该在这里做什么,所以我不能建议修复。希望有所帮助!
答案 2 :(得分:2)
除了Dan的答案之外,你可以简单地在那里推动追踪,这将显示问题。
solve s | s == 0 = Nothing
| s == 1 = Just 1
| otherwise =
trace (show s) $ check [solve (s-(x*2)) | x <- [1..9]]
答案 3 :(得分:2)
你可以使用模式匹配重写第一部分,它比守卫(if-statements)更好的表示法;)
solve 0 = Nothing
solve 1 = Just 1
solve s = check [solve (s - (x * 2)) | x <- [1..9]]
列表推导将范围1到9提供给solve方法,该方法调用solve with
s - (x * 2)
老实说,我不能直觉地告诉那将会终止......但让我们考虑一些例子。
solve 2
调用求解2将导致以下列表,因为Haskell很懒,列表将没有值,直到你(有副作用)尝试打印这些...
solve s - 1 * 2
solve s - 2 * 2
solve s - 3 * 2
solve s - 4 * 2
solve s - 5 * 2
solve s - 6 * 2
solve s - 7 * 2
solve s - 8 * 2
solve s - 9 * 2
一个简单的solve 2
会尝试solve -2
,它会尝试解决其他问题,并且“不会结束。”
答案 4 :(得分:1)
solve s | s == 0 = Nothing
| s == 1 = Just 1
| otherwise =
check [solve (s-(x*2)) | x <- [1..9]]
如果是solve 2
:
(2 - (1 * 2)) = 0
(0 - (2 * 2)) = -2
等等。
我不确定调试的东西,但这就是它溢出堆栈的原因。它无限递归。
答案 5 :(得分:0)
check :: [Maybe a] -> Maybe a
check = Data.Maybe.listToMaybe . Data.Maybe.catMaybes
solve :: (Num a, Num b) => a -> Maybe b
solve 0 = Nothing
solve 1 = Just 1
solve s = solve (s-2)
在这里,很明显solve -1
和solve 5.3
将无限运行。
这个版本的求解将像while循环一样运行。
您发布的原始版本会在每次调用不需要的东西时将垃圾邮件发送到您的ram /堆栈中。
你可以改写这个:
solve s = check [solve (s-x)|x<-[2,4..18]]
到此:
solve s = check [solve (s-2),solve (s-4),solve (s-6),solve (s-8),solve (s-10),solve (s-12),solve (s-14),solve (s-16),solve (s-18)]
但只要solve (s-2)
返回Nothing,那么每个solve (s-x)
都会返回Nothing,因为该值已经过如下测试:solve ((((s-2)-2)-2)-2)
它是一种测试sth的指数算法,可以在线性时间内测试或在恒定时间内计算。