具有列表的haskell-foldr操作

具有列表的haskell-foldr操作,haskell,fold,Haskell,Fold,给定一个负数和正数序列的列表,如何使用foldr将它们划分为负数和正数序列 例如[1,2,3,-1,-2,-3,1,2,3]我将得到[1,2,3],-1,-2,-3],[1,2,3]] 一些疑问 我如何知道我已经比较过的前一个分区与我正在比较的分区具有相同的符号 如何将元素添加到列表中?我尝试了类似于[x]:y的东西,但是我得到的是每个元素作为一个列表并连接在一起,这不是结果 我现在拥有的是这个 foldr (\ x y -> if x >= 0 then [x]:y else

给定一个负数和正数序列的列表,如何使用foldr将它们划分为负数和正数序列

例如[1,2,3,-1,-2,-3,1,2,3]我将得到[1,2,3],-1,-2,-3],[1,2,3]]

一些疑问

我如何知道我已经比较过的前一个分区与我正在比较的分区具有相同的符号

如何将元素添加到列表中?我尝试了类似于[x]:y的东西,但是我得到的是每个元素作为一个列表并连接在一起,这不是结果

我现在拥有的是这个

foldr (\ x y -> if  x >= 0  then [x]:y else y ) [[]] 
哪个是错的


非常感谢您提前提供的帮助。

使用最好的工具完成这项工作。在这种情况下,该作业的最佳工具是

groupBy
将列表中的两个成员传递给您的函数,以便您可以轻松检查它们是否具有相同的符号


(如果你真的想写,你可以用
foldr
来写,你可以用
foldr
来写
groupBy
,尽管标准的实现没有这样做,但它只会让事情变得比需要的更复杂。)

您可以使用
数据列表中的
groupBy
等工具获取所需信息

import Data.List (groupBy)
let result = groupBy (\ x y -> x*y>0) [1,2,3,-1,-2,-3,1,2,3]

如果您不想单独处理
0
,请使用例如Daniel Fischer的
sameSign
函数进行检查。

您想将列表中每个数字的符号与其后续数字的符号进行比较。如果符号相同,则希望将
x
与其后续符号放在同一列表中,否则将启动一个新的内部列表

所以

将执行您想要的操作(给定
sameSign
的实现)。但这并不是很有效(而且根本不适用于无限列表),因为要知道使用哪一个等式,需要构造
x
之后的部分,这意味着必须先到达输入列表的末尾,然后才能返回列表

解决方案是惰性,您必须在检查第二个参数之前开始构造结果

combine x wss = (x:ssx) : rest
  where
    (ssx:rest) = case wss of
                   [[]] -> [] : []
                   (yys@(y:ys) : zss)
                       | sameSign x y -> yys : zss
                       | otherwise    -> [] : wss
然后

是你想要的,比如

sameSign x y
    | x < 0     = y < 0
    | otherwise = y >= 0
sameSign x y
|x<0=y<0
|否则=y>=0

(当然,使用
groupBy
更短、更容易,但这并不使用
foldr
:)

我将使用foldr提供可能的答案。我不是说你应该使用它,因为它既不是非常有效(我使用a*b>=0来表示a和b是同一符号),也不适用于无限列表

combine = foldr f []
    where
        f a [] = [[a]]
        f a rest@((x:xs):ys) | x*a >= 0 = (a:x:xs):ys
                             | otherwise = [a]:rest

我支持使用
groupBy
。然而,我想提出一点,0在数学中不是一个正数。正如迄今为止没有其他答案提到的那样,
Num
typeclass的任何东西都必须实现
signum
,它将返回给定给它的数字的符号

import Data.List     (groupBy)
import Data.Function (on) -- Can evade a lambda

signGroup :: (Num a) => [a] -> [[a]]
signGroup = groupBy ((==) `on` signum)
用法示例:

> signGroup [1,2,3,0,0,-1,-2,1,2,0,3,4,-1]
[[1,2,3],[0,0],[-1,-2],[1,2],[0],[3,4],[-1]]

这里需要一个稍微复杂一点的累加器:

data Sign = Neg | Zero | Pos

signGroup :: [Integer] -> [[Integer]]
signGroup xs = case
  foldr
  (\x (sign, ps, ns, ys) ->
    -- x    - current element
    -- sign - sign of the prev. group
    -- ps   - positive numbers in the current group
    -- ns   - negative numbers in the current group
    -- ys   - final list
    if x >= 0
    then case sign of
      Neg  -> (Pos, x : ps, [], ns : ys)
      Zero -> (Pos, x : ps, [], ys)
      Pos  -> (Pos, x : ps, [], ys)
    else case sign of
      Neg  -> (Neg, [], x : ns, ys)
      Zero -> (Neg, [], x : ns, ys)
      Pos  -> (Neg, [], x : ns, ps : ys))
  (Zero, [], [], [])
  xs
 of
    (_, [], [], ys) -> ys
    (_, [], ns, ys) -> ns : ys
    (_, ps, [], ys) -> ps : ys
    (_, ps, ns, ys) -> ps : ns : ys -- <- unreachable

-- signGroup [1,2,3,-1,-2,-3,1,2,3]
-- => [[1,2,3],[-1,-2,-3],[1,2,3]]
data Sign=Neg | Zero | Pos
签名组::[Integer]->[[Integer]]
符号组xs=case
福尔德
(\x(符号、ps、ns、ys)->
--x-电流元件
--签名-上一组的标志
--ps-当前组中的正数
--ns-当前组中的负数
--ys-最终名单
如果x>=0
那么案例的迹象呢
负->(位置,x:ps,[],ns:ys)
零->(位置,x:ps,[],Y)
Pos->(Pos,x:ps,[],ys)
其他情况下的迹象
负->(负,[],x:ns,ys)
零->(负,[],x:ns,ys)
位置->(负,[],x:ns,ps:ys))
(零、[]、[]、[])
xs
属于
(u,[],[],ys)->ys
(u,[],ns,ys)->ns:ys
(u,ps,[],ys)->ps:ys
(ps,ns,ys)->ps:ns:ys--[1,2,3],-1,-2,-3],[1,2,3]]

@Landei,是的,它太复杂了;)丹尼尔·费舍尔的答案有一个更好的文件夹功能。
> signGroup [1,2,3,0,0,-1,-2,1,2,0,3,4,-1]
[[1,2,3],[0,0],[-1,-2],[1,2],[0],[3,4],[-1]]
data Sign = Neg | Zero | Pos

signGroup :: [Integer] -> [[Integer]]
signGroup xs = case
  foldr
  (\x (sign, ps, ns, ys) ->
    -- x    - current element
    -- sign - sign of the prev. group
    -- ps   - positive numbers in the current group
    -- ns   - negative numbers in the current group
    -- ys   - final list
    if x >= 0
    then case sign of
      Neg  -> (Pos, x : ps, [], ns : ys)
      Zero -> (Pos, x : ps, [], ys)
      Pos  -> (Pos, x : ps, [], ys)
    else case sign of
      Neg  -> (Neg, [], x : ns, ys)
      Zero -> (Neg, [], x : ns, ys)
      Pos  -> (Neg, [], x : ns, ps : ys))
  (Zero, [], [], [])
  xs
 of
    (_, [], [], ys) -> ys
    (_, [], ns, ys) -> ns : ys
    (_, ps, [], ys) -> ps : ys
    (_, ps, ns, ys) -> ps : ns : ys -- <- unreachable

-- signGroup [1,2,3,-1,-2,-3,1,2,3]
-- => [[1,2,3],[-1,-2,-3],[1,2,3]]