Haskell sublist with foldr - haskell

I'm trying to make a function in haskell but my goal is doing it by using foldr over list, this is an example:
sublistas [5,1,2]
[[],[2],[1],[1,2],[5],[5,2],[5,1],[5,1,2]]
efficiency is not an issue. What I try so far gives to me the error:
cannot construct the infinite type .....
sublistas = foldr (\x rs -> [x] ++ map (x:) rs) [[]]
I tried a long time, maybe someone could give me some ideas here?

You can use:
foldr (\x rs -> rs ++ map (x:) rs) [[]]
For example:
Prelude> foldr (\x rs -> rs ++ map (x:) rs) [[]] [5,1,2]
[[],[2],[1],[1,2],[5],[5,2],[5,1],[5,1,2]]
The proposed foldr thus works as follows: we start with a [[]]. Now for an element x, we generate the concatenation, of all lists already generated (in the first step [], and these lists prepended with the element, so [2]).
So after a first step, we obtain [[],[2]]. Next we fold again and now we generate [[],[2],[1],[1,2]]. Finally we also work with 5, resulting in [[],[2],[1],[1,2],[5],[5,2],[5,1],[5,1,2]].
The above explanation has to be seen in a lazy manner: rs is not necessary calculated (first), unless that is necessary.
Your lambda expression \x rs -> [x] ++ map (x:) rs is incorrect for two reasons:
[x] is a list containing a item of the list you provide, not a list of lists of items you provide, so a type error; and
you should not add an [x] to the result anyway: you pass all elements that are already generated, together with all the elements you prepend with x.

Related

Implement recursion using foldl in haskell

given the below code
pair :: [String] -> [(String,String)]
pair [] = []
pair (x:xs)= zip [x] xs ++ pair xs
how could I rewrite it using Fold to avoid repetition ?
A fold is going to be a bit messy for this particular problem because your folding function depends upon the previously visited elements in the list, with a two-value list minimum. And since folding visits elements one at a time, you have to decide what to do when there's only one element in the list.
Here is an example that creates a dummy element for the singleton list case and discards it with init.
pair :: [String] -> [(String, String)]
pair = init . foldr f []
where
f x acc =
case acc of
[] -> [(x, "discarded")]
z#(y:_) -> (x, fst y) : z
If you're tasked with learning about folds, take a minute to understand why we have to handle it in such an unsatisfactory way. Otherwise, if you're looking to do this in the least amount of code, see #DavideSpataro's answer above of zip xs (tail xs).

Generating subsets of set. Laziness?

I have written a function generating subsets of subset. It caused stack overflow when I use in the following way subsets [1..]. And it is "normal" behaviour when it comes to "normal" (no-lazy) languages. And now, I would like to improve my function to be lazy.
P.S. I don't understand laziness ( And I try to understand it) so perhaps my problem is strange for you- please explain. :)
P.S. 2 Feel free to say me something about my disability in Haskell ;)
subsets :: [a] -> [[a]]
subsets (x:xs) = (map (\ e -> x:e) (subsets xs)) ++ (subsets xs)
subsets [] = [[]]
There's two problems with that function. First, it recurses twice, which makes it exponentially more ineffiecient than necessary (if we disregard the exponential number of results...), because each subtree is recalculated every time for all overlapping subsets; this can be fixed by leting the recursive call be the same value:
subsets' :: [a] -> [[a]]
subsets' [] = [[]]
subsets' (x:xs) = let s = subsets' xs
in map (x:) s ++ s
This will already allow you to calculate length $ subsets' [1..25] in a few seconds, while length $ subsets [1..25] takes... well, I didn't wait ;)
The other issue is that with your version, when you give it an infinite list, it will recurse on the infinite tail of that list first. To generate all finite subsets in a meaningful way, we need to ensure two things: first, we must build up each set from smaller sets (to ensure termination), and second, we should ensure a fair order (ie., not generate the list [[1], [2], ...] first and never get to the rest). For this, we start from [[]] and recursively add the current element to everything we have already generated, and then remember the new list for the next step:
subsets'' :: [a] -> [[a]]
subsets'' l = [[]] ++ subs [[]] l
where subs previous (x:xs) = let next = map (x:) previous
in next ++ subs (previous ++ next) xs
subs _ [] = []
Which results in this order:
*Main> take 100 $ subsets'' [1..]
[[],[1],[2],[2,1],[3],[3,1],[3,2],[3,2,1],[4],[4,1],[4,2],[4,2,1],[4,3],[4,3,1],[4,3,2],[4,3,2,1],[5],[5,1],[5,2],[5,2,1],[5,3],[5,3,1],[5,3,2],[5,3,2,1],[5,4],[5,4,1],[5,4,2],[5,4,2,1],[5,4,3],[5,4,3,1],[5,4,3,2],[5,4,3,2,1],[6],[6,1],[6,2],[6,2,1],[6,3],[6,3,1],[6,3,2],[6,3,2,1],[6,4],[6,4,1],[6,4,2],[6,4,2,1],[6,4,3],[6,4,3,1],[6,4,3,2],[6,4,3,2,1],[6,5],[6,5,1],[6,5,2],[6,5,2,1],[6,5,3],[6,5,3,1],[6,5,3,2],[6,5,3,2,1],[6,5,4],[6,5,4,1],[6,5,4,2],[6,5,4,2,1],[6,5,4,3],[6,5,4,3,1],[6,5,4,3,2],[6,5,4,3,2,1],[7],[7,1],[7,2],[7,2,1],[7,3],[7,3,1],[7,3,2],[7,3,2,1],[7,4],[7,4,1],[7,4,2],[7,4,2,1],[7,4,3],[7,4,3,1],[7,4,3,2],[7,4,3,2,1],[7,5],[7,5,1],[7,5,2],[7,5,2,1],[7,5,3],[7,5,3,1],[7,5,3,2],[7,5,3,2,1],[7,5,4],[7,5,4,1],[7,5,4,2],[7,5,4,2,1],[7,5,4,3],[7,5,4,3,1],[7,5,4,3,2],[7,5,4,3,2,1],[7,6],[7,6,1],[7,6,2],[7,6,2,1]]
You can't generate all the subsets of an infinite set: they form an uncountable set. Cardinality makes it impossible.
At most, you can try to generate all the finite subsets. For that, you can't proceed by induction, from [] onwards, since you'll never reach []. You need to proceed inductively from the beginning of the list, instead of the end.
A right fold solution would be:
powerset :: Foldable t => t a -> [[a]]
powerset xs = []: foldr go (const []) xs [[]]
where go x f a = let b = (x:) <$> a in b ++ f (a ++ b)
then:
\> take 8 $ powerset [1..]
[[],[1],[2],[2,1],[3],[3,1],[3,2],[3,2,1]]

Is `group list by size` a fold?

I came across this problem : grouping the elements of a list by packet of the same size, so that
> groupBy 3 [1..10]
[[1,2,3], [4,5,6], [7,8,9], [10]]
Nothing really hard to do, but first I was surprise that I couldn't find a function for it.
My first try was
groupBy _ [] = []
groupBy n xs = g : groupBy n gs
where (g, gs) = splitAt n xs
So far so good, it works, even on infinite list. However I don't like the first line groupBy _ [] = []. Seems a good candidate for a fold but I couldn't figure it out.
So can this function can be written as a fold or as a one liner ?
Update
My attempt at a one liner:
groupBy' n l = map (map snd) $ groupBy ((==) `on` fst) $ concatMap (replicate n) [1..] `zip` l
It took me 10 times more to write that the initial attempt.
Update 2
Following Ganesh answer and using unfoldr and the help of pointfree I came out with this convoluted point free solution
groupBy' n = unfoldr $ listToMaybe . (ap (>>) (return.splitAt n))
You can do it as a fold with some gymnastics, but it's much nicer as an unfold:
unfoldr (\xs -> if null xs then Nothing else Just (splitAt n xs))
[You'll need to import Data.List if you haven't already]
The type of unfoldr is:
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
The idea of unfoldr is that a generating function decides whether to stop (Nothing) or keep going (Just). If the result is Just then the first element of the tuple is the next element of the output list, and the second element is passed to the generating function again.
As #leftroundabout pointed out in a comment on the question, an unfold is much more natural here because it treats the output list elements as similar to each other, whereas in a fold the input list elements should be treated similarly. In this case the need to start a new sublist every n elements of the input list makes this harder.

How do I split a list into sublists at certain points?

How do I manually split [1,2,4,5,6,7] into [[1],[2],[3],[4],[5],[6],[7]]? Manually means without using break.
Then, how do I split a list into sublists according to a predicate? Like so
f even [[1],[2],[3],[4],[5],[6],[7]] == [[1],[2,3],[4,5],[6,7]]
PS: this is not homework, and I've tried for hours to figure it out on my own.
To answer your first question, this is rather an element-wise transformation than a split. The appropriate function to do this is
map :: (a -> b) -> [a] -> [b]
Now, you need a function (a -> b) where b is [a], as you want to transform an element into a singleton list containing the same type. Here it is:
mkList :: a -> [a]
mkList a = [a]
so
map mkList [1,2,3,4,5,6,7] == [[1],[2],...]
As for your second question: If you are not allowed (homework?) to use break, are you then allowed to use takeWhile and dropWhile which form both halves of the result of break.
Anyway, for a solution without them ("manually"), just use simple recursion with an accumulator:
f p [] = []
f p (x:xs) = go [x] xs
where go acc [] = [acc]
go acc (y:ys) | p y = acc : go [y] ys
| otherwise = go (acc++[y]) ys
This will traverse your entire list tail recursively, always remembering what the current sublist is, and when you reach an element where p applies, outputting the current sublist and starting a new one.
Note that go first receives [x] instead of [] to provide for the case where the first element already satisfies p x and we don't want an empty first sublist to be output.
Also, this operates on the original list ([1..7]) instead of [[1],[2]...]. But you can use it on the transformed one as well:
> map concat $ f (odd . head) [[1],[2],[3],[4],[5],[6],[7]]
[[1,2],[3,4],[5,6],[7]]
For the first, you can use a list comprehension:
>>> [[x] | x <- [1,2,3,4,5,6]]
[[1], [2], [3], [4], [5], [6]]
For the second problem, you can use the Data.List.Split module provided by the split package:
import Data.List.Split
f :: (a -> Bool) -> [[a]] -> [[a]]
f predicate = split (keepDelimsL $ whenElt predicate) . concat
This first concats the list, because the functions from split work on lists and not list of lists. The resulting single list is the split again using functions from the split package.
First:
map (: [])
Second:
f p xs =
let rs = foldr (\[x] ~(a:r) -> if (p x) then ([]:(x:a):r) else ((x:a):r))
[[]] xs
in case rs of ([]:r) -> r ; _ -> rs
foldr's operation is easy enough to visualize:
foldr g z [a,b,c, ...,x] = g a (g b (g c (.... (g x z) ....)))
So when writing the combining function, it is expecting two arguments, 1st of which is "current element" of a list, and 2nd is "result of processing the rest". Here,
g [x] ~(a:r) | p x = ([]:(x:a):r)
| otherwise = ((x:a):r)
So visualizing it working from the right, it just adds into the most recent sublist, and opens up a new sublist if it must. But since lists are actually accessed from the left, we keep it lazy with the lazy pattern, ~(a:r). Now it works even on infinite lists:
Prelude> take 9 $ f odd $ map (:[]) [1..]
[[1,2],[3,4],[5,6],[7,8],[9,10],[11,12],[13,14],[15,16],[17,18]]
The pattern for the 1st argument reflects the peculiar structure of your expected input lists.

Filter elements of a list of lists that contain elements of a list

So, to explain the mouthful that is the question...
I'm trying to use filter, and not getting anywhere. So here's the behaviour I want. Given a list of lists (of Integers) ie
[[1,2,3],[23456,4,3,2],[1,3,4,5,6],[3,2,1],[4,2,1],[5,6,7],[1,2,5]]
I want to take another list ie [1,2] and take all the lists that contain both those elements. (It doesn't matter if any of the others are preserved at this moment in time, though that might be needed later). So in this example my output would be something like
[[1,2],[2,1],[2,1],[1,2]]
or preferably
[[1,2,3],[3,2,1],[4,2,1],[1,2,5]]
First, define what it means for the elements of one list to be a subset of another:
> let xs `isSubsetOf` ys = all (`elem` ys) xs
Then you can just partially apply this function to get a suitable predicate to filter by:
> let xss = [[1,2,3],[23456,4,3,2],[1,3,4,5,6],[3,2,1],[4,2,1],[5,6,7],[1,2,5]]
> filter ([1, 2] `isSubsetOf`) xss
[[1,2,3],[3,2,1],[4,2,1],[1,2,5]]
That'll do for small inputs. For larger inputs, you might want to use Data.Set instead of lists.
ghci> import Data.Set hiding (filter)
ghci> let subset xs ys = fromList xs `isSubsetOf` fromList ys
ghci> let xs = [[1,2,3],[23456,4,3,2],[1,3,4,5,6],[3,2,1],[4,2,1],[5,6,7],[1,2,5]]
ghci> filter (subset [1,2]) xs
[[1,2,3],[3,2,1],[4,2,1],[1,2,5]]
So you want to keep a list candidate if all elements of the list criterion are also elements of candidate. Thus your filter condition is
condition candidate = all (`elem` candidate) criterion
which, using flip we can write as
condition candidate = flip all criterion (flip elem candidate)
thus giving
filter (flip all criterion . flip elem)
similars :: Eq a => [a] -> [[a]] -> [[a]]
similars xs = filter (\ ys -> all (`elem` ys) xs)
meaning
similars [1,2] [[1,2,3],[23456,4,3,2],[1,3,4,5,6],[3,2,1],[4,2,1],[5,6,7],[1,2,5]]
==s
[[1,2,3],[3,2,1],[4,2,1],[1,2,5]]

Resources