我有二元搜索树的玩具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
答案 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
;)