Haskell的show
通常以递归方式实现:
data Tree = Node Tree Tree | Leaf
show' (Node left right) = "(Node " ++ show' left ++ " " ++ show' right ++ ")"
show' Leaf = "Leaf"
main = putStrLn $ show' (Node (Node Leaf Leaf) Leaf)
如何使用尾递归实现show
?
答案 0 :(得分:6)
使用CPS,如M. Shaw所述。
show' :: Tree -> String
show' = \tree -> go tree id
where
go (Node left right) c =
go left (\l -> go right (\r -> c ("(Node " ++ l ++ " " ++ r ++ ")")))
go Leaf c = c "Leaf"
重要的是要记住,在许多情况下,Haskell的懒惰消除了对尾递归的需要。在这种情况下,尾递归版必须遍历整个树,然后才能返回任何输入部分。尝试使用每个版本显示无限树。当以惰性语言返回诸如String
之类的惰性结构时,最好是corecursive(与原始实现相比)而不是尾递归。
此函数的大部分时间都会被左嵌套(++)
调用占用,其左侧参数为O(n)
。解决方案是使用difference list,这是一种延续传递方式本身。
另见Continuation-Based Program Transformation Strategies,其中讨论了如何通过转换为CPS来获得有效的算法,然后将延续的结构转换为更具体的结果,以达到尾递归解决方案。
答案 1 :(得分:4)
你可以通过Continuation passing style转发这个尾递归。看看维基页面上的例子。