Haskell拆分列表函数无限类型错误

Haskell拆分列表函数无限类型错误,haskell,Haskell,我正在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中,并将第一个列

我正在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,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功能。不确定如何着手修复此错误。有什么想法吗?

没有什么建议

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

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

  • 当您将
    ([(长度(x:y:xs)
    div
    2)-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')
几点建议

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

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

  • 当您将
    ([(长度(x:y:xs)
    div
    2)-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')

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

对于如何附加列表和元素,您也有一些困惑。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]

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

对于如何附加列表和元素,您也有一些困惑。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]

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

而不是

split2 (0:xs:[y:ys])
您应该像下面这样将不同的参数/值分别传递给函数

split2 n xs (y:ys)
您正在寻找的功能也在标准库函数中重现

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

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

而不是

split2 (0:xs:[y:ys])
您应该像下面这样将不同的参数/值分别传递给函数

split2 n xs (y:ys)
您正在寻找的功能也在标准库函数中重现

halveList xs = splitAt (length xs `div` 2) xs
splitEO [] = ([], [])
splitEO [e] = ([e], [])
splitEO (e:o:xs) = (e:es, o:os) where (es, os) = splitEO xs