Haskell 您如何实施;“显示”;递归跟踪?
Haskell的Haskell 您如何实施;“显示”;递归跟踪?,haskell,tail-recursion,Haskell,Tail Recursion,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 你可以通过递归的方式来扭转
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
你可以通过递归的方式来扭转这条尾巴。看看wiki页面上的示例。使用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(您的原始实现就是这样)而不是tail recursive
此函数的大部分时间将被左嵌套的(++)
调用占用,这在其左参数中是O(n)
。解决方案是使用a,这是延续传递样式本身的一种形式
另请参见,其中讨论了如何通过转换为CPS来实现高效算法,然后将连续体的结构转换为更具体的结构,以获得尾部递归解决方案。我感兴趣的是,是否存在将具有多个递归分支的非尾部递归函数明显转换为尾部递归对应函数的情况。我认为你必须使用拉链才能保持它的效率,这是错误的吗?因为累积结构需要在每次尾部调用时进行深度编辑?CPS本质上使累积结构成为一种功能,其功能强大到足以“深度编辑”啊,好吧!这很合适,谢谢各位。Haskell的
showsPrec
不是通过让你们提供一个函数a->ShowS
来解决这个问题吗?不确定,但我就是这么想的?@AlecshowsPrec
比show
更有效,但它不是尾部递归的。然而,这是因为在Haskell中,show
是尾部递归(参见luqui提到的corecursivity)是没有意义的。