实现mapTree函数

tal*_*tal 3 binary-tree dictionary haskell

我要求定义函数:

treeMap :: (a -> b) -> BinaryTree a -> BinaryTree b
Run Code Online (Sandbox Code Playgroud)

它接受一个函数和一个二叉树,并生成一个二叉树,其中所有节点都是在给定树上应用该函数的结果

二进制树是:

data BinaryTree a = Nil | BNode a (BinaryTree a) (BinaryTree a)
Run Code Online (Sandbox Code Playgroud)

和我的代码不符合。我收到以下错误:

error: Not in scope: data constructor ‘BinaryTree’
treeMap f (BNode x (BinaryTree l) (BinaryTree r)) =    |                                    ^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

我的代码:

data BinaryTree a = Nil | BNode a (BinaryTree a) (BinaryTree a)

treeMap :: (a -> b) -> BinaryTree a -> BinaryTree b
treeMap f Nil  = Nil
treeMap f (BNode x (BinaryTree l) (BinaryTree r)) =
    BNode (f x) (BinaryTree (treeMap f l)) (BinaryTree (treeMap f r))
Run Code Online (Sandbox Code Playgroud)

Wil*_*sem 9

你的模式(BNode x (BinaryTree l) (BinaryTree r))不是一个有效的模式。实际上,二叉树的数据定义表明:

data BinaryTree a = Nil | BNode a (BinaryTree a) (BinaryTree a)
Run Code Online (Sandbox Code Playgroud)

因此,这意味着它BNode是一个包含三个参数的数据构造函数。最后两个参数的类型BinaryTree a,但是您不能在模式匹配中使用类型。

因此,您应该使用lr作为这些参数的变量(或者您可以使用该BinaryTree a类型的数据构造函数)。

构造BinaryTree a类型时相同。用BNode x l r和调用构造函数xl然后r使用值,而不在表达式中指定类型。您可以指定类型,然后使用::运算符。

因此,您可以使用以下方法修复代码:

treeMap :: (a -> b) -> BinaryTree a -> BinaryTree b
treeMap f Nil  = Nil
treeMap f (BNode x l r) = BNode (f x) (treeMap f l) (treeMap f r)
Run Code Online (Sandbox Code Playgroud)

或更优雅:

treeMap :: (a -> b) -> BinaryTree a -> BinaryTree b
treeMap f = go
    where go Nil = Nil
          go (BNode x l r) = BNode (f x) (go l) (go r)
Run Code Online (Sandbox Code Playgroud)

话虽如此,您可以使用编译指示为您ghc派生Functor实例DeriveFunctor

{-# LANGUAGE DeriveFunctor #-}

data BinaryTree a = Nil | BNode a (BinaryTree a) (BinaryTree a) deriving Functor
Run Code Online (Sandbox Code Playgroud)

treeMap只是fmap :: Functor f => (a -> b) -> f a -> f bf ~ BinaryTree在这里。

  • 看来OP混淆了数据类型定义的类型级别和值级别部分,这并不奇怪,因为Haskell98语法并未真正区分它们。最近我一直喜欢GADTSyntax,它可以让您编写data BinaryTree :: Type-> Type其中{Nil :: BinaryTree a; BNode :: a-> BinaryTree a-> BinaryTree a-> BinaryTree a}`,而imo更清楚地表明`BinaryTree`是* type *构造函数,而不是* data *构造函数;这也使得以后更容易引入`GADTs'。 (2认同)