我试图根据列表中的索引/位置将列表拆分为偶数和奇数。例如,对于列表[2,3,6]
,结果应该是even = [2,6]
和odd = [3]
。
我想使用不使用列表推导式的方法——一次匹配两个元素,并将一个放在偶数列表中,另一个放在奇数列表中。
但我不确定的语法得到它的工作。我知道如何在逻辑上,但我在努力与语法。以下是目前为止的内容:
splitOnPos :: [a] -> ([a], [a])
splitOnPos [] = ([], [])
splitOnPos (x1:x2:xs) = (odds, evens)
where
odds = x1 : splitOnPos xs
evens = x2 : splitOnPos xs
我得到以下关于类型的错误:
* Couldn't match expected type `[a]' with actual type `([a], [a])'
* In the second argument of `(:)', namely `splitOnPos xs'
In the expression: x2 : splitOnPos xs
In an equation for `evens': evens = x2 : splitOnPos xs
你差一点就成功了。应该是
splitOnPos :: [a] -> ([a], [a])
splitOnPos [] = ([], [])
splitOnPos (x1:x2:xs) = (x1:odds, x2:evens)
where
(odds, evens) = splitOnPos xs
正如错误消息提醒您的那样,该函数返回元组(一对)列表,而不仅仅是一个列表,您可以(:
)访问任何内容。
因此,我们接受元组,并将两个头元素分别添加到相应的列表中,再次将结果重新打包为一对,因此类型适合:
( x1:odds <-- ( odds
, , <---- recursive call
x2:evens ) <-- evens )
你还要在这里写一个方程,这样就涵盖了所有的情况。现在您只处理空列表的情况,以及包含两个或两个以上元素的列表。
不处理单例列表的情况。因此,它只适用于偶数长度的列表:
> splitOnPos [0..9]
([0,2,4,6,8],[1,3,5,7,9])
> splitOnPos [0..10]
([0,2,4,6,8*** Exception: <interactive>:(574,1)-(577,37):
Non-exhaustive patterns in function splitOnPos
我通过添加一个列表只包含一个元素的大小写来修复代码。这不应该有任何例外。基本上它会把x和y发送到不同的列表。X作为第一个元素总是奇数,而y作为第二个元素总是偶数。
splitOE :: [Int] -> ([Int],[Int])
splitOE [] = ([],[])
splitOE [x] = ([x],[])
splitOE (x:y:xs) = (x:odds, y:evens)
where
(odds, evens) = splitOE xs