Creating tuples variations from a list - Haskell - list

I am a relative haskell newbie and am trying to create a list of tuples with an equation I named splits that arises from a single list originally, like this:
splits [1..4] --> [ ([1],[2,3,4]), ([1,2],[3,4]), ([1,2,3],[4]) ]
or
splits "xyz" --> [ ("x","yz"), ("xy","z") ]
Creating a list of tuples that take 1, then 2, then 3 elements, etc. I figured out I should probably use the take/drop functions, but this is what I have so far and I'm running into a lot of type declaration errors... Any ideas?
splits :: (Num a) => [a] -> [([a], [a])]
splits [] = error "shortList"
splits [x]
| length [x] <= 1 = error "shortList"
| otherwise = splits' [x] 1
where splits' [x] n = [(take n [x], drop n [x])] + splits' [x] (n+1)

The Haskell-y approach is to use the inits and tails functions from Data.List:
inits [1,2,3,4] = [ [], [1], [1,2], [1,2,3], [1,2,3,4] ]
tails [1,2,3,4] = [ [1,2,3,4], [2,3,4], [3,4], [4], [] ]
We then just zip these two lists together and drop the first pair:
splits xs = tail $ zip (inits xs) (tails xs)
or equivalently, drop the first element of each of the constituent lists first:
= zip (tail (inits xs)) (tail (tails xs))

splits [] = []
splits [_] = []
splits (x:xs) = ([x], xs) : map (\(ys, zs) -> (x:ys, zs)) (splits xs)

You have several mistakes.
You don't need to have Num a class for a.
use [] or [x] as pattern, but not a variable, use xs instead.
Use ++ instead of + for concatenating lists.
In our case use (:) to add list to value instead of ++.
Add stop for recursion, like additional variable maxn to splits'
splits :: [a] -> [([a], [a])]
splits [] = error "shortList"
splits xs
| lxs <= 1 = error "shortList"
| otherwise = splits' xs 1 lxs
where
lxs = length xs
splits' xs n maxn
| n > maxn = []
| otherwise = (take n xs, drop n xs) : splits' xs (n+1) maxn

There is a built in function that kind of does a part of what you want:
splitAt :: Int -> [a] -> ([a], [a])
which does what it looks like it would do:
> splitAt 2 [1..4]
([1,2],[3,4])
Using this function, you can just define splits like this:
splits xs = map (flip splitAt xs) [1..length xs - 1]

Related

How to combine list of lists with list of lists

I have lists of lists and need to combine it with another list of lists.
Example inputs:
A: [[1,2],[3,4],[5,6],[7,8]]
B: [[1,2],[3,4],[5,6],[7,8]]
Example output:
[[1,2,1,2],[1,2,3,4],..,[7,8,5,6],[7,8,7,8]]
2 lists of lists with 4 lists inside both would return us a list of lists size 4*4 = 16
I've tried just recursively combine the lists, but i know it wouldn't work even if would go through.
mergeAll [[]] [[]] = [[]]
mergeAll [[]] b = b
mergeAll a [[]] = a
mergeAll xs ys = mergeAll (merge xs ys) (drop 1 ys)
merge :: [[a]] -> [[a]] -> [[a]]
merge [[]] [[]] = [[]]
merge xs [[]] = xs
merge [[]] ys = ys
merge (x:xs) (y:ys) = ((x++y):xs)
You can use a list comprehension:
[ xs ++ ys | xs <- listOfLists1, ys <- listOfLists2 ]
You may do like
Prelude> let doit = \as bs -> as >>= \a -> bs >>= \b -> pure (a ++ b)
Prelude> doit [[1,2],[3,4],[5,6],[7,8]] [[1,2],[3,4],[5,6],[7,8]]
[[1,2,1,2],[1,2,3,4],[1,2,5,6],[1,2,7,8],[3,4,1,2],[3,4,3,4],[3,4,5,6],[3,4,7,8],[5,6,1,2],[5,6,3,4],[5,6,5,6],[5,6,7,8],[7,8,1,2],[7,8,3,4],[7,8,5,6],[7,8,7,8]]
As Robin says in a comment, you can also do it like:
liftA2 (++)
I ask my self a question trying to understand why that is equivalent to:
[xs ++ ys | xs <- xss, ys <- yss]

Haskell: List manipulation

I want to write a function which takes a input list and manipulates it in the following way:
Step 1: Take the first element of the list and the last element of the list and put it together in a sublist.
Step 2: Take the second element of the list and the second last element of the list and put it together in the next sublist.
Step 3: Take the third element of the list and the third last element of the
list and put it together in next sublist.
Continue this according to the same scheme (for a list of n elements)...
If the number of elements of the input list is odd the n/2 element of the input list will be added as last sublist of the output list.
Example:
[1,2,3,4,5,6,7]
-- should be transformed to
[[1,7],[2,6],[3,5],[4]]
I already wrote a function which takes every 2 elements of a list and puts it together in sublists and I am wondering if this code might help me with my problem above:
g2 :: [a] -> [[a]]
g2 [] = []
g2 (x1:x2:xs) = [x1,x2]: g2 xs
g2 xs = [xs]
Here's one that does it in one pass:
pairs :: [a] -> [[a]]
pairs xs = fst (go xs xs) where
go (x:xs) (_:_:ys) = f x (go xs ys)
go (x:xs) [_] = ([[x]],xs)
go xs [] = ([],xs)
f x (xs,y:ys) = ([x,y]:xs,ys)
How does it work? Let's look at the first two arguments of go first, and in particular this line:
go (x:xs) (_:_:ys) = f x (go xs ys)
Those two arguments are both from the same list (xs), but we take 2 items off of one, and only one off of the other. Why? So we know when we hit the halfway point. Look at this function for comparison:
halfway xs = go xs xs
where
go (_:xs) (_:_:ys) = go xs ys
go xs _ = xs
>>> halfway [1..6]
[4,5,6]
Now, once we get to the halfway point we'll need to "zip" it with the other list. But it needs to be in reverse! How do we do this? A handy way to reverse any function in one pass is to first write it as a fold. Here's zip written as a fold:
zip = foldr (\x k (y:ys) -> (x,y) : k ys) (const [])
To "reverse" it, you just apply is as a foldl rather than as a foldr (you also have to flip the closure).
For our uses, we basically build up the base as we go (in the form of k). So no our function looks like this:
pairs :: [a] -> [[a]]
pairs xs = go xs xs (const []) where
go (y:ys) (_:_:zs) k = go ys zs (f y k)
go (y:ys) [_] k = [y] : k ys
go ys [] k = k ys
f x k (y:ys) = [x,y] : k ys -- same `f` as from `zip`
There's still one problem: the list is returned in the wrong order. To fix this, we replace the list with a difference list, and swap the order of the appends.
Finally, we un-CPS the function, and we get the above.
Here's one using transpose
import Data.List
g2 xs =
transpose [take (x + y) xs, take x (reverse xs)]
where (x, y) = (length xs) `divMod` 2
Note that we have to use drop 1 instead of tail here to avoid errors for odd-length lists.
g2 :: [a] -> [[a]]
g2 [] = []
g2 xs = [first xs] ++ (g2 . drop 1 $ init xs)
where first (x:[]) = [x]
first xs = [head xs, last xs]
Two more, the second is using unfoldr:
pair xs = take (length xs `div` 2) $ zip xs (reverse xs)
-- Note: uses tuples instead of lists
import Data.List
pairs2 = unfoldr (\xs ->
if length xs < 2
then Nothing
else Just ([head xs, last xs], init.tail $ xs))
xs = [2,3,4,7,6]
pair xs -- [(2,6),(3,7)]
pair2 xs -- [[2,6],[3,7]]

How to fix the error ('cannot construct the infinite type') in my code and how to make my code work

Basically i'm trying to do a function where you are given a list and a number and you have to split the list in lists of the same size as the number given and the last split of all can have a length lower than the number given
separa a xs = if length xs >= a then separaM a (drop a xs) ([take a xs]) else [xs]
separaM a xs yss = if length xs >= a then separaM a (drop a xs) (yss : (take a xs)) else separaM a [] (yss : xs)
separaM a [] yss = yss
I expect the output of 3 "comovais" to be ["com","ova","is"] but in my program there is no output because of the error
Note that the expression:
yss : (take a xs)
(take a xs) has type [b], so yss has type b. But when you pass yss : (take a xs) as an argument to separaM function, yss is expected has type [b] not b. That is why the error occurred.
Actually, you don't need yss to store the result, the recursive function can be defined as:
separaM _ [] = []
separaM a xs = (if length xs >= a then (take a xs) else xs) :
separaM a (drop a xs)
Your code has some errors in it. Tweaking your misuse of (:) gets it to pass the type-checker:
separa a xs
| length xs >= a = go a (drop a xs) [take a xs]
| otherwise = [xs]
where
go a xs yss
| length xs >= a = go a (drop a xs) (yss ++ [take a xs])
-- was: (yss : (take a xs))
| otherwise = go a [] (yss ++ [xs])
-- was: (yss : xs)
go a [] yss = yss
but it's better to further change it to
separa :: Int -> [a] -> [[a]]
separa a xs
| length xs >= a = go a (drop a xs) [take a xs]
| otherwise = [xs]
where
go a xs yss
| length xs >= a = go a (drop a xs) ([take a xs] ++ yss)
| otherwise = reverse ([xs] ++ yss)
It works:
> separa 3 [1..10]
[[1,2,3],[4,5,6],[7,8,9],[10]]
This is a common "build in reverse, then reverse when built" idiom, frequently seen in strict functional languages. Some of them allow for lists to be built in top-down, natural order, by a technique known as tail-recursion modulo cons. Haskell is lazy, and lets us build its lists in top-down manner naturally and easily, with the equivalent guarded recursion:
separa :: Int -> [a] -> [[a]]
separa a xs
| length xs >= a = go a (drop a xs) [take a xs]
| otherwise = [xs]
where
go a xs yss
| length xs >= a = -- go a (drop a xs) (yss ++ [take a xs])
yss ++ go a (drop a xs) [take a xs]
| otherwise = -- go a [] (yss ++ [xs])
yss ++ [xs]
There's an off-by-one error here; I'll leave it for you to fix on your own.
But sometimes the infinite type is inherent to a problem, and not a result of a programming error. Then we can fix it by using recursive types.
Whenever we get type equivalency t ~ a..b..t..c.., we can start by defining a type
newtype T = MkT (a..b..T..c..)
then see which type variables are free and close over them, as
newtype T a b c = MkT (a..b..(T a b c)..c..)
An example: Infinite type error when defining zip with foldr only; can it be fixed?

Remove duplicate but keep the order

rmdup :: [Int] -> [Int]
rmdup [] = []
rmdup (x:xs) | x `elem` xs = rmdup xs
| otherwise = x: rmdup xs
The code above removes duplicate from a list of Integer but it removes the first occurrence and keeps the second one. For instance:
rmdup [1,2,3,1,4]
will result:
[2,3,1,4]
How can I change it to keep the order and yield this: [1,2,3,4]? Note, I don't want to use built-in functions.
How about the following? This avoids the crazily inefficient acc ++ [x] and also to reverse the given list twice:
rmdup :: Eq a => [a] => [a]
rmdup xs = rmdup' [] xs
where
rmdup' acc [] = []
rmdup' acc (x:xs)
| x `elem` acc = rmdup' acc xs
| otherwise = x : rmdup' (x:acc) xs
One way to achieve what you want is to pass the input list in the reverse order and once when the computation is finished then reverse the result again. Although, this solution is not efficient.
rmdup :: [Int] -> [Int]
rmdup xs = reverse $ rmdup' (reverse xs)
where
rmdup' [] = []
rmdup' (x:xs) | x `elem` xs = rmdup' xs
| otherwise = x: rmdup' xs
Demo:
ghci> rmdup [1,2,3,1,4]
[1,2,3,4]
You want to ignore those later occurrences of an element if you saw it before, then you need to record what you have seen, looks like foldl or foldl' is what you are looking for.
Here is a possible implementation:
import Data.List (foldl')
rmdup :: (Eq a) => [a] -> [a]
rmdup = foldl' step []
where step acc x
| x `elem` acc = acc
| otherwise = acc++[x]
Since elem is O(n), the solutions based on using it to check each element are O(n^2).
The "standard" efficient solution to the duplicates problem is to sort the list before checking for duplicates. Here, since we need to preserve elements, we have to be a bit more careful.
import Data.List
import Data.Ord
rmdupSorted :: Eq b => [(a,b)] -> [(a,b)]
rmdupSorted (x#(_,xb):xs#((_,yb):_)) | xb == yb = rmdupSorted xs
| otherwise = x : rmdupSorted xs
rmdupSorted xs = xs -- 0 or 1 elements
rmdup :: Ord a => [a] -> [a]
rmdup = map snd . sort . rmdupSorted . sortBy (comparing snd) . zip [0..]
main = print $ rmdup [1,2,3,4,5,4,6,1,7]
Assuming that the sortBy function is a stable sort, the rmdup function will remove all the duplicate occurrences of any element but for the one occurring last. If sortBy is not stable, then rmdup will remove all the occurrences but for an unspecified one (i.e., rmdup [1,2,1] could return [1,2] instead of [2,1].).
Complexity is now O(n log n).
We now need to rewrite the above without library functions, as the OP requested. I will leave this as an exercise to the reader. :-P

How to compute frequency via list comprehension?

count :: Eq a => a -> [a] -> Int
count n [] = 0
count n (x:xs) | n == x = 1 + count n xs
| otherwise = count n xs
rmdups :: Eq a => [a] -> [a]
rmdups [ ] = [ ]
rmdups (x:xs) = x : rmdups (filter(/= x) xs)
using the 2 functions, a third needs to be created, called frequency:
it should count how many times each distinct value in a list occurs in that list. for example : frequency "ababc", should return [(3,'a'),(2,'b'),(1,'c')].
the layout for frequency is :
frequency :: Eq a => [a] -> [(Int, a)]
P.s rmdups, removes duplicates from list, so rmdups "aaabc" = abc
and count 2 [1,2,2,2,3] = 3.
so far i have:
frequency :: Eq a => [a] -> [(Int, a)]
frequency [] = []
frequency (x:xs) = (count x:xs, x) : frequency (rmdups xs)
but this is partly there, (wrong). thanks
frequency xs = map (\c -> (count c xs,c)) (rmdups xs)
or, with a list comprehension,
frequency xs = [(count c xs, c) | c <- rmdups xs]
is the shortest way to define it using your count and rmdups. If you need it sorted according to frequency (descending) as in your example,
frequency xs = sortBy (flip $ comparing fst) $ map (\c -> (count c xs,c)) (rmdups xs)
using sortBy from Data.List and comparing from Data.Ord.
If all you have is an Eq constraint, you cannot gain much efficiency, but if you only need it for types in Ord, you can get a much more efficient implementation using e.g. Data.Set or Data.Map.
Here is my own 'lazy' answer, which does not call rmdups:
frequency [] = []
frequency (y:ys) = [(count y (y:ys), y)] ++ frequency (filter (/= y) ys)
import qualified Data.Set as Set
frequency xs = map (\x -> (length $ filter (== x) xs, x)) (Set.toList $ Set.fromList xs)