【问题标题】:Increment node values in Tree [Haskell]增加树中的节点值 [Haskell]
【发布时间】:2018-07-31 19:20:58
【问题描述】:

我正在尝试实现一个 haskell 程序,该程序使用函子增加树中所有节点的值。函子函数的输入和输出是一棵树。我正在尝试以递归方式实现它,但在输入参数方面出现编译错误。

Haskell 代码..

data Tree v = Empty | Node v (Tree v) (Tree v) deriving (Show)

add :: Ord v => v -> Tree v -> Maybe Tree v
add _ Empty = Nothing
add v (Node val left right) = (val + v) ++ add v left ++ add v right

输入

add (+1) (Node 3 (Node 1 Empty Empty) (Node 7 (Node 4 Empty Empty) Empty))

输出

  [1 of 1] Compiling Main             ( functor1.hs, interpreted )

  functor1.hs:17:34: error:
  * Expecting one fewer arguments to `Maybe Tree'
   Expected kind `* -> *', but `Maybe Tree' has kind `*'
  * In the type signature:
    add :: Ord v => v -> Tree v -> Maybe Tree v
       |
 17    | add :: Ord v => v -> Tree v -> Maybe Tree v
       |                                  ^^^^^^^^^^^^

  functor1.hs:17:40: error:
  * Expecting one more argument to `Tree'
    Expected a type, but `Tree' has kind `* -> *'
  * In the first argument of `Maybe', namely `Tree'
   In the type signature:
    add :: Ord v => v -> Tree v -> Maybe Tree v
   |
17 | add :: Ord v => v -> Tree v -> Maybe Tree v
   |                                        ^^^^
 Failed, no modules loaded.

语法有错误吗?请帮忙

【问题讨论】:

  • 不,它更符合语义。你写(val + v) ++ add v left ++ add v right,但(val + v) ++ add v left ++ add v rightMaybe Tree 怎么样?此外,您应该写Maybe (Tree v),并且v 也应该是Num 的一个实例。
  • 此外,您的问题定义了一个函数add,但错误是关于fmap1
  • 你缺少括号:add :: Ord v => v -> Tree v -> Maybe (Tree v)

标签: haskell recursion functional-programming


【解决方案1】:

我正在尝试以递归方式实现它,但在输入参数方面出现编译错误。

没有错误已经在编译时,所以add 永远不会编译,因此它不起作用。

语法和语义都存在一些问题,以及一些奇怪的设计决策。

首先,如果你写Maybe Tree v,Haskell 将其视为(Maybe Tree) v,据我所知,这不是预期的结果,它应该是Maybe (Tree v),因为你包装了Tree v变成Maybe

但是使用Maybe (Tree v)作为结果已经有点奇怪了:不管你提供什么输入树,我们应该总是构造一个new有效的Tree。对于Empty,我们根本不添加任何值,所以add 3 Empty == Empty,但没有可能出错的场景。

您还将Ord v 用作类型约束,这很奇怪,因为在函数中,我们从不使用==/=<> 等函数。我们使用+,这意味着我们应该使用Num v,所以现在我们的签名是:

add :: Num v => v -> Tree v -> Tree v

我们可以实现两种情况:一种用于Empty(保持Empty),另一种用于Node(更新值,并执行两次递归调用),例如:

add :: Num v => v -> Tree v -> Tree v
add _ Empty = Empty
add v (Node x l r) = Node (v+x) (add v l) (add v r)

您的问题表明您要实现Functor。定义fmap 与此处的add 非常相似,但需要概括第一个参数。我把它留作练习。

如果你调用它:

add (+1) (Node 3 (Node 1 Empty Empty) (Node 7 (Node 4 Empty Empty) Empty))

第一个参数不是一个数字,而是一个函数,所以在这种情况下你应该去掉+

add 1 (Node 3 (Node 1 Empty Empty) (Node 7 (Node 4 Empty Empty) Empty))

制作:

Prelude> add 1 (Node 3 (Node 1 Empty Empty) (Node 7 (Node 4 Empty Empty) Empty))
Node 4 (Node 2 Empty Empty) (Node 8 (Node 5 Empty Empty) Empty)

【讨论】:

  • 我尝试了您的解决方案,但是当我传递输入时,我收到错误“* 约束中的非类型变量参数:Num (a -> a)(使用 FlexibleContexts 来允许这样做)*检查推断类型时 :: forall a. (Num (a -> a), Num a) => Tree (a -> a) "
  • 但如果我不想改变调用函数的方式,那么我只需要改变函数参数吗?
  • @Lucy:正如 cmets 中所述,您需要进一步概括该函数(到 fmap1),这留作练习。
猜你喜欢
  • 2023-04-10
  • 1970-01-01
  • 2021-12-04
  • 1970-01-01
  • 2021-08-12
  • 2021-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多