我正在尝试基于给定谓词实现列表拆分器。该功能类似于递归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
答案 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''