【问题标题】:Couldn't match expected type `Int' with actual type `a'无法将预期类型“Int”与实际类型“a”匹配
【发布时间】:2019-11-11 15:03:35
【问题描述】:
import Data.List

data Tree a = Leaf a | Node (Tree a) a (Tree a) deriving Show

toTree :: Ord a => [a] -> Tree a
toTree xs = Node (balancedTree (take n xs')) (xs'!!n) (balancedTree (drop n xs'))
    where 
        xs' = sort xs
        n = middle xs

middle :: Num a => [a] -> a
middle xs = fromIntegral ((length xs `div` 2) + 1)

balancedTree :: Ord a => [a] -> Tree a
balancedTree (x:[]) = Leaf x
balancedTree xs = Node (balancedTree (take n xs')) (xs'!!n) (balancedTree (drop n xs'))
    where 
        xs' = sort xs
        n = middle xs

这是我从列表转换为二叉树的代码。我知道有很多错误,但我只想在开始调试之前对类型错误进行排序。我在“toTree”方法和“balancedTree”方法中都得到了以下错误,因为它们实际上是相同的,并且在错误被排除后将被压缩为一个。

ex7.hs:6:38: error:
    * Couldn't match expected type `Int' with actual type `a'
      `a' is a rigid type variable bound by
        the type signature for:
          toTree :: forall a. Ord a => [a] -> Tree a
        at ex7.hs:5:1-32
    * In the first argument of `take', namely `n'
      In the first argument of `balancedTree', namely `(take n xs')'
      In the first argument of `Node', namely
        `(balancedTree (take n xs'))'
    * Relevant bindings include
        xs' :: [a] (bound at ex7.hs:8:9)
        n :: a (bound at ex7.hs:9:9)
        xs :: [a] (bound at ex7.hs:6:8)
        toTree :: [a] -> Tree a (bound at ex7.hs:6:1)
  |
6 | toTree xs = Node (balancedTree (take n xs')) (xs'!!n) (balancedTree (drop n xs'))
  |                                      ^

我已经尝试了几个小时通过搜索 stackOverflow 来修复它,但我无法弄清楚。 “toTree”的类型声明必须保持不变。树的定义也应该保持不变。

我的理解是“take”需要一个“Int”,我给它一个“a”。我不知道如何解决这个问题。

【问题讨论】:

  • 您是否尝试阅读并理解错误消息?错误有什么不清楚的地方?
  • 你的树形结构错误。例如,它不能表示具有两个数据项的树。
  • 我建议从函数insert :: Ord a => a -> Tree a -> Tree a 开始。获取包含 N 项的树,返回包含 N+1 项的树。不要乱用排序和索引。
  • 如果您正在与特定的人交谈,请使用@username 约定,然后他们会收到通知。如果你问我,我的意思就是我所说的。您的树数据结构不能表示具有两个数据项的树。你想试着在一张纸上画出这样一棵树,看看为什么不可能。
  • 你可能需要解雇你的老师。

标签: haskell


【解决方案1】:

问题在于middle 返回一个a,而不是Int。确实:

middle :: Num a => [a] -> a
middle xs = fromIntegral ((length xs `div` 2) + 1)

但是在您的balancedTree 中,您将其用作索引,而take n、drop n 和!! n 要求n 是Int,确实:

balancedTree :: Ord a => [a] -> Tree a
balancedTree (x:[]) = Leaf x
balancedTree xs = Node (balancedTree (take n xs')) (xs'!!n) (balancedTree (drop n xs'))
    where 
        xs' = sort xs
        n = middle xs

类型签名也没有多大意义。您可以计算任何列表的长度,而不仅仅是由数字组成的列表。因此,您应该构造一个返回列表中间的 index 的函数并使用它。例如:

middle :: [a] -> Int
middle = (length xs `div` 2) + 1

话虽如此,在 Haskell 中使用 length 等通常不是一个好主意。 length 需要 O(n) 时间,而且对于无限列表,它会陷入无限循环。通常,如果您使用 length 之类的函数,会有更优雅的解决方案。

与其使用“自上而下”的方法,不如使用“自下而上”的方法,在其中迭代项目,并即时构造Leafs,并将它们组合在一起在Nodes 中,直到您到达顶部。

【讨论】:

  • 您可能希望drop (n + 1) xs' 避免将中间元素存储在根和的右子树中。 (或take (n-1) xs')。
猜你喜欢
  • 2018-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-29
  • 2019-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多