给出二叉树
data BinaryTree a =
Leaf
| Node (BinaryTree a) a (BinaryTree a)
deriving (Show)
我的预订/订购解决方案是使用:
preorder :: BinaryTree a -> [a]
preorder Leaf = []
preorder (Node left x right) = x : preorder left ++ preorder right
inorder :: BinaryTree a -> [a]
inorder Leaf = []
inorder (Node left x right) = inorder left ++ (x : inorder right)
但是对于后期订单,这没有用:
postorder :: BinaryTree a -> [a]
postorder Leaf = []
postorder (Node left x right) = (postorder left ++ postorder right) : x
并且理所当然,因为我发现类型签名是
(:) :: a -> [a] -> [a]
我以为我可以通过以下方式解决这个问题:
append :: [a] -> a -> [a]
append = flip (:)
postorder :: BinaryTree a -> [a]
postorder Leaf = []
postorder (Node left x right) = (postorder left ++ postorder right) `append` x
但它最终给了我与preorder
相同的答案。我感到很困惑,因为我认为左手边会在右手边进行评估。
我认为这是因为我知道postorder也可以像这样解决(不是这种方法的粉丝,因为它意味着无缘无故地将x作为一个列表而是追加):
postorder (Node left x right) = postorder left ++ postorder right ++ [x]
有人可以告诉我哪里出错了,也许为什么邮购顺序与预订相同?
答案 0 :(得分:2)
让我们使用等式推理来查看postorder
与append
失败的位置。
append = flip (:)
(postorder left ++ postorder right) `append` x
-- bring append to front
append (postorder left ++ postorder right) x
-- substitute append
flip (:) (postorder left ++ postorder right) x
-- expand flip
(\f x y -> f y x) (:) (postorder left ++ postorder right) x
-- partially apply expanded flip
(\x y -> y : x) (postorder left ++ postorder right) x
-- finish application
x : (postorder left ++ postorder right)
现在,因为我们知道一般(x : y) ++ z === x : (y ++ z)
我们可以看到你的" postorder"方法实际上等同于您的预订方法!
你所犯的错误在于试图考虑评价的顺序,以及像#34这样的想法的理由;左手边将在右手边评估"。从这种等式方法可以看出,在纯懒惰的功能设置中,评估顺序基本上可以忽略不计。重要的是通过替换和简化函数本身来实现。
如果您不想将x
添加到列表中只是为了追加它,请执行此操作,编写函数
consEnd :: [a] -> a -> [a]
直接在列表末尾插入内容。