如何基于谓词实现列表拆分器

时间:2018-04-27 16:12:04

标签: haskell

我正在尝试基于给定谓词实现列表拆分器。该功能类似于递归break.I在列表中输入,并且我将元素附加到小列表,只要给定给定谓词元素为真。当谓词为假时,我将形成的列表追加到一个更大的列表中,并且我继续从那里继续忽略与假谓词相对应的元素。

P.S:我试图不使用任何只有自我实现的Data.List函数。(我正处于学习阶段)。 例如:

输入
 谓词:(\x->x<3)
           列表:[1,2,3,2,3,1,1,1,3]
输出[[1,2],[2],[1,1,1]]

到目前为止,我尝试过以下方法: 我使用一个列表给出一个列表,它在2的元组中打破它。第一个元素是列表,直到假谓词。第二个是其余的。我将这个元组提供给一次又一次执行此操作的函数。

splt::(a->Bool)->[a]->[[a]]
    splt p []=[]
    splt p (x:xs)=go p [] (x:xs) where
                  go p rez []=rez
                  go p rez ls=rez:process . brk $  ls [] where
                  process  (x,[])=rez:x
                  process ([],x)=go p rez x


    brk::(a->Bool)->[a]-> ([a],[a])
    brk p []= ([],[])
    brk p (x:xs)=go p ([],x:xs) where 
                 go p (accu,[])= (accu,[])
                 go p (accu,x:xs)|not (p x) =(accu,xs)
                                 |otherwise = go p (x:accu,xs)

我收到以下错误:cannot produce infinite type.

我也尝试过一个更简单的解决方案:

format::(a->Bool)->[a]->[[a]]
   format p []=[]
   format p ls=go p [] [] ls where
               go p small big []=small:big
               go p small big (x:xs)=case p x of 
                                     True ->go p x:small big xs
                                     False ->go p [] small:big xs     

但它不起作用,我也必须在两种情况下都反转结果。我得到的错误是:

* Couldn't match type `a' with `[a0]'
      `a' is a rigid type variable bound by
        the type signature for:
          wrds :: forall a. (a -> Bool) -> [a] -> [[a]]
        at Ex84.hs:12:5-31
      Expected type: [a0] -> Bool
        Actual type: a -> Bool
    * In the first argument of `go', namely `p'
      In the expression: go p [] []
ls

2 个答案:

答案 0 :(得分:2)

这是实现所需内容的一种方式。

我所做的是使用函数span,它将列表分成两部分,返回一个元组。第一个元素是满足p的初始元素列表。元组的第二个元素是列表的其余部分。

我递归地使用了这个,同时丢弃了不满足p的元素。

splt :: (a -> Bool) -> [a] -> [[a]]
splt p [] = []
splt p ls = let (a,rs)  = span p ls
                (b,rs') = span (not . p) rs
            in if null a then splt p rs' else a : splt p rs'

您也可以尝试自己定义span

答案 1 :(得分:2)

第二个问题只是一个包围问题,可以通过正确地将参数括起来来解决问题:

case p x of 
    True ->go p (x:small) big xs
    False ->go p [] (small:big) xs 

如果不这样做,列表将被视为功能。在这种情况下,您还必须在结果列表中反向映射。

您也可以尝试使用span功能:

splt :: (a -> Bool) -> [a] -> [[a]]
splt _ [] = []
splt p xs = let (xs', xs'') = span p xs
                remaining   = dropWhile (not . p) xs''
            in case xs' of
              []  -> splt p remaining
              xs' -> xs' : splt p xs''