我需要帮助。 我有这种形式的功能
myFunction = case myFunction of
(Nothing) -> (Just)
(Just) -> (Just)
我想让它尾递归。 如何做到这一点? 我理解,根据递归调用的返回,我们有一个不同的语句,这使得它很难(我需要帮助的原因^^)。 我可以提供原始功能,但我更愿意寻找更通用的解决方案。 提前致谢
修改:实际代码:
myFunction :: MyTree x -> (x, Maybe(MyTree x))
myFunction = (x, Nothing)
myFunction (MyNode left right) = case myFunction left of
(x, Nothing) -> (x, Just right)
(x, Just left2) -> (x, Just (Node left2 right))
答案 0 :(得分:1)
我假设你定义了
data MyTree x = MyLeaf x | MyNode (MyTree x) (MyTree x)
并且意味着
myFunction :: MyTree x -> (x, Maybe(MyTree x))
myFunction (MyLeaf x) = (x, Nothing)
myFunction (MyNode left right) = case myFunction left of
(x, Nothing) -> (x, Just right)
(x, Just left2) -> (x, Just (MyNode left2 right))
这是一个拉出最左边的叶子并将相应的右分支缝合在一起的函数。
你问如何使这个尾递归。这是为什么?在一些(严格)语言中,尾递归代码更有效,但Haskell使用惰性求值,这意味着递归调用发生的时间并不重要,而是它们产生输出的时间。在这种情况下,头部递归case myFunction left of
向下缩放到树下直到找到最左边的叶子,你不能更快地到达它。然而,在回来的路上,它确实通过了x
而不是立即返回,但是它也在适当的平面上重新缝合所有正确的分支而没有任何记账,这是使用递归的乐趣在递归数据结构上。
请参阅this question,了解为什么尾递归不是Haskell中效率最重要的因素。
在节点上使用数据对二叉树做的三件经典事情是: 1.预先遍历遍历(先访问当前节点然后再访问左子树) - 双尾递归 2.有序遍历(访问左子树,然后是当前节点,然后右) - 头部和尾部递归 3.后序遍历(在当前节点之前访问左右子树) - 双头递归。
对于不习惯懒惰评估的人来说,发布命令听起来令人担忧,但这是一种有效的方法来对树中的值求和,例如,特别是如果你确保编译器知道它是严格的。
与往常一样,最好的算法可以提供最快的结果,如果要打开优化,则应该使用-O2进行编译。
答案 1 :(得分:0)
这些必须匹配。
myFunction = ...
myFunction (MyNode left right) = ...
他们不匹配。你不能一起使用它们。为什么?其中一个采用零参数,另一个采用一个参数。他们必须采用相同数量的论点。如果您需要忽略参数,请使用_
。请注意,使用_
的版本必须位于不使用_
的版本之后。
myFunction :: MyTree x -> Maybe (MyTree x)
myFunction (MyNode left right) =
case myFunction left of
Nothing -> Just right
Just left2 -> Just (MyNode left2 right)
myFunction _ = Nothing
我不知道x
应该在你的函数体中是什么。它不受任何限制。
这不是尾递归。并非所有函数都可以构成尾递归函数。
也许如果您描述了该功能应该做什么,我们可以帮助您做到这一点。