无法将预期的类型“ Int”与实际类型“ a”匹配

时间:2019-11-11 15:03:35

标签: haskell

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”。我不知道该如何解决。

1 个答案:

答案 0 :(得分:1)

问题是middle返回a,而不是Int。确实:

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

但是在您的balancedTree中,您将其用作索引,take ndrop 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

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

与其使用“自上而下”的方法,不如使用“自下而上”的方法,其中遍历所有项目并动态构建Leaf,然后分组可能更好。 Node秒内将它们一起放到顶部。