【问题标题】:Haskell Split List Function Infinite Type ErrorHaskell拆分列表函数无限类型错误
【发布时间】:2012-09-29 08:47:53
【问题描述】:

我正在使用 Haskell 中的一个函数,它将一个列表分成两个大小均匀的列表。这是我所拥有的:

split (x:y:xs) = split2 ([((length(x:y:xs) `div` 2)-2) : x ++ y] : [xs])
split2 (x:xs:[y:ys]) = split2 ((x-1) : [xs] ++ y : [ys])
split2 (0:xs:[y:ys]) = (xs:[y:ys])

该函数获取列表的前两个元素,并将它们放在列表 #2 中,并将第一个列表作为第二个元素附加。然后它获取列表的长度,并将其除以 2 以找出运行次数,同时考虑到它已经从第一个列表中删除了两个元素。然后它获取这两条信息并将其放入 split2 中,它从第一个列表中获取另一个元素并将其附加到第一个元素中的第二个列表中,它还会从运行次数中倒数 1,然后再次运行。

问题是,当我运行它时,我得到了这个:

Functions.hs:19:49:
    Occurs check: cannot construct the infinite type: t0 = [t0]
    In the first argument of `(:)', namely `(y)'

19 指的是第 2 行,第一个 split2 函数。不完全确定如何解决此错误。有什么想法吗?

【问题讨论】:

    标签: haskell


    【解决方案1】:

    一些建议

    • 将类型写入所有函数。它使代码更具可读性,也有助于捕捉错误。

    • ++ 的类型是 [a] -> [a] -> [a],并且您正在添加列表的长度以及元素。由于 list 必须是统一类型且长度返回 Int 类型,因此编译器将 split 类型推断为 [[Int]] -> t(假设 split2 返回类型 t)。

    • 当您将 ([((length(x:y:xs)div2)-2) : x ++ y] : [xs]) 传递给 split2 时。 xs[[Int]] 类型,这意味着 [xs][[[Int]]] 类型 ,因此编译器将split2 的类型推断为[[[Int]]] -> t

    现在在 split2 的定义中

     split2 (x:xs:[y:ys]) = split2 ((x-1) : [xs] ++ y : [ys])
    

    ys[[Int]] 类型,所以 y[Int] 类型。 xs[[Int]] 类型,但你正在使用 [xs] ++ y,这意味着 [xs]y 应该是同一类型([a] 用于某些 a)。

    由于您没有提供任何类型,编译器完全不知道如何推断这种类型。

    如果您只是想将列表分成两个相等的部分,为什么不做一些更简单的事情,比如

    split3 :: [a] -> ([a], [a])
    split3 [] = ([],[])
    split3 [x] =  ([x],[])
    split3 (x:y:xs) = let (xs',ys') = split3 xs in (x:xs',y:ys')
    

    【讨论】:

      【解决方案2】:

      在 Haskell 中,列表的元素必须是同一类型。在您的函数中,列表包含 Ints、原始列表的元素和原始列表的子列表的混合,所有这些都可能是不同的类型。

      您还对如何附加列表和元素有些困惑。 x ++ y 只能在 x 和 y 本身是列表时使用,而 x : y 只能在 y 是列表且 x 是列表的元素时使用;要创建一个包含 x 和 y 作为元素的新列表,请改用 [x, y] (尽管 x:[y] 也可以)。同样 [xs] ++ y 需要改为 xs ++ [y]。

      在不改变基本算法的情况下,最简单的解决方案可能是让 split2 采用 3 个单独的参数。

      split (x:y:xs) = split2 ((length(x:y:xs) `div` 2)-2) [x,y] xs
      split2 n xs (y:ys) = split2 (n-1) (xs++[y]) ys
      split2 0 xs ys = [xs,ys]
      

      【讨论】:

        【解决方案3】:

        您似乎是在列表中传递状态而不是作为值传递给函数,当编译器看起来好像您正在创建异构值列表时会产生问题,而 Haskell 中的列表应该是同类型的。

        代替

        split2 (0:xs:[y:ys])
        

        您应该像这样将不同的参数/值分别传递给函数

        split2 n xs (y:ys)
        

        您正在寻找的功能也在标准库函数中重现。

        halveList xs = splitAt (length xs `div` 2) xs
        

        【讨论】:

          【解决方案4】:

          很难知道从哪里开始......

          让我们从split2 中更大的表达式块定义函数。

          f1 (x:y:xs) = (length(x:y:xs) `div` 2)-2
          f1 :: [a] -> Int
          

          好的,所以参数是一个列表,它返回一个Int

          f2 (x:y:xs) = ((length(x:y:xs) `div` 2)-2) : x
          f2 :: [[Int]] -> [Int]
          

          这里,lengthIntx 相矛盾,所以x 必须是[Int],所以(x:y:xs) 必须是[[Int]]。我们也可以推断出yx是同类型的,而xs是同类型事物的列表; [[Int]]。所以x ++ y 也将是[Int]

          所以,[xs] 将具有类型 [[[Int]]]。现在,我们将结果包装在一个列表构造函数中,并将其与[xs] 结合起来:

          f3 (x:y:xs) = [((length(x:y:xs) `div` 2)-2) : x ++ y] : [xs]
          f3 :: [[Int]] -> [[[Int]]]
          

          我猜你没想到参数是Ints 的列表列表。

          现在,如果我们查看split2,参数模式(x:xs:[y:ys]) 暗示它属于以下类型:

          split2 :: [[a]] -> b
               x :: [a]
              xs :: [a]
               y ::  a
              ys :: [a]
          

          split2 的第一个定义的 rhs 尝试通过连接 (x-1) : [xs]y : [ys] 来构造一个新列表。但是,如果我们将类型替换为y : [ys],我们会发现:

          y : [ys] :: a : [[a]]
          

          但是由于(:) :: a -> [a] -> [a],这就意味着[[a]]必须和[a]是同一类型,或者a必须是自己的一个列表,这是不可能的。

          (x-1) 也输入错误,因为它试图从列表中减去一个。

          我不知道您是想将列表拆分为偶数和奇数元素,还是分成前半部分和后半部分。

          这里有两个版本,分为前半部分和后半部分,如果长度为奇数,则向下取整 (RD) 或向上取整 (RU):

          splitRD xs = splitAt (length xs `div` 2) xs
          splitRU xs = splitAt ((length xs + 1) `div` 2) xs
          

          这是一个将列表分成偶数和奇数元素的版本:

          splitEO [] = ([], [])
          splitEO [e] = ([e], [])
          splitEO (e:o:xs) = (e:es, o:os) where (es, os) = splitEO xs
          

          【讨论】:

            猜你喜欢
            • 2021-08-05
            • 2012-02-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-05-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多