Haskell-如何基于BinaryTree的文件夹创建mapTree函数?

问题描述

这是第11章“从第一原理进行Haskell编程”的代数数据类型中的一个问题:

data BinaryTree a =
  Leaf
  | Node (BinaryTree a) a (BinaryTree a)
  deriving (Eq,Ord,Show)

我们实际上并没有在现有树中插入值;每次我们想在数据结构中插入一个值时,我们都会构建一棵新树:

insert' :: Ord a => a -> BinaryTree a -> BinaryTree a
insert' b Leaf = Node Leaf b Leaf
insert' b (Node left a right)
  | b == a = Node left a right
  | b < a = Node (insert' b left) a right
  | b > a = Node left a (insert' b right)

这是BinaryTree数据结构的映射函数

mapTree :: (a -> b) -> BinaryTree a -> BinaryTree b
mapTree _ Leaf = Leaf
mapTree f (Node left a right) = 
  Node (mapTree f left) (f a) (mapTree f right)

为BinaryTree编写文件

鉴于我们提供的BinaryTree的定义,为二叉树写一个同构关系。

-- any traversal order is fine
foldTree :: (a -> b -> b) 
  -> b 
  -> BinaryTree a 
  -> b

上面的类型是对那些在应用折叠功能之前不将树转换为列表的提示

为BinaryTree重写映射

使用您刚刚编写的foldTree,使用foldTree重写mapTree。 没有Ord约束是有意的,您无需使用insert函数

mapTree' :: (a -> b)
  -> BinaryTree a
  -> BinaryTree b
mapTree' f bt =
  foldTree undefined undefined undefined

在很多帮助下,我设法获得了一个有关文件夹的第一个问题的答案: https://github.com/johnchandlerburnham/hpfp/blob/master/11/BinaryTree.hs

我的答案:

foldTree f b Leaf = b
foldTree f b (Node left a right) 
  = (foldTree f tempb left) where
    tempb = (f a) tempright
    tempright = foldTree f b right

但是,关于为BinaryTree编写新的mapTree的第二个问题,我找不到答案。上面提供了原始的mapTree。甚至johnchandlerburnham link的答案都使用了不同的折叠树。

有人可以根据我对第一个问题的回答来帮助您获得第二个问题的答案吗?还是第一个问题需要另一个答案?

用于测试的树可能是:

testTree :: BinaryTree Integer
testTree =
  Node (Node Leaf 3 Leaf) 1 (Node Leaf 4 Leaf)

解决方法

您不能使用带有该签名的mapTree来写foldTree。 (正如@chi指出的那样,技术问题是foldTree的签名错误,是BinaryTree的真实写法。)实际上,如果加载了链接的Haskell文件BinaryTree.hs,您会发现那里的mapTree'无法正常工作:

λ> :l BinaryTree
λ> mapTree (+1) testTree
Node (Node Leaf 2 Leaf) 3 (Node Leaf 4 Leaf)
λ> mapTree' (+1) testTree
Node (Node (Node Leaf 3 Leaf) 2 Leaf) 4 Leaf

它给出了正确的节点值,但是树的结构是错误的。

我没有这本书的副本,因此我无法确切看到您所看到的内容,但是也许these notes会有所帮助。在第11.15节的最后,作者讨论了foldTree的2参数和3参数版本,并表明只有为使用3参数版本而编写的mapTree'才能正常工作。