在Haskell的树上遍历打印

时间:2014-10-06 03:14:23

标签: haskell tree

我有二元搜索树的玩具haskell代码。函数preorderV是使用应用于每个元素的函数遍历树。它适用于正常功能。但是,如果我应用函数“print”,我得到编译错误。如何使用preorderV使IO工作相关的功能?

由于

代码:

data BSTree a = EmptyTree | Node a (BSTree a) (BSTree a) deriving (Show)
data Mode = IN | POST | PRE

singleNode :: a -> BSTree a
singleNode x = Node x EmptyTree EmptyTree

bstInsert :: (Ord a) => a -> BSTree a -> BSTree a
bstInsert x EmptyTree = singleNode x
bstInsert x (Node a left right)
          | x == a = Node a left right
          | x < a  = Node a (bstInsert x left) right
          | x > a  = Node a left (bstInsert x right)

buildTree :: String -> BSTree String
buildTree = foldr bstInsert EmptyTree . words    

preorderV :: (a->b) -> BSTree a -> BSTree b
preorderV f EmptyTree = EmptyTree
preorderV f (Node x left right) = Node (f x) (preorderV f left) (preorderV f right)

错误:

Couldn't match type ‘BSTree’ with ‘IO’
Expected type: IO (IO ())
  Actual type: BSTree (IO ())
In a stmt of a 'do' block: preorderV print $ buildTree content

2 个答案:

答案 0 :(得分:3)

preorderV print $ buildTree content的类型是BSTree (IO ()),也就是说,您正在创建IO计算的二叉树 - 您自己没有IO计算。

要做我认为你想做的事,你需要创建一个preorderV的monadic版本,它有以下类型:

preorderVM :: (a -> IO ()) -> BSTree a -> IO ()
preorderVM f EmptyTree = ... -- what do you want to do here?
preorderVM f (Node x left right) = do
    f x 
    preorderVM f left
    preorderVM f right

答案 1 :(得分:1)

到目前为止,您的代码仍有效,但有BSTree (IO ())后退,当您在do阻止(最有可能main)内使用时,您会收到错误。

您现在可以做的是折叠在树上以恢复操作,然后您可以使用sequence或与使用相似的内容一个接一个的行动:

foldT :: (a -> s -> s) -> s -> BSTree a -> s
foldT _ s EmptyTree = s
foldT f s (Node a left right) =
  let s' = foldT f s left
      s'' = f a s'
  in foldT f s'' right

main :: IO ()
main = do
  let doPrint = preorderV print $ buildTree "C A B D E"
      folded = foldT (:) [] doPrint
  sequence_ . reverse $ folded

这将打印

λ> :main
"A"
"B"
"C"
"D"
"E"

BTW :您的preorderV通常称为map;)