I am working on trying to reverse a nested list in Haskell. I am aware that nested lists are not a thing in Haskell so I defined one:
data NestedList a = Elem a | SubList [NestedList a]
I also have a flatten function:
flatten :: NestedList a -> [a]
flatten (Elem x) = [x]
flatten (SubList x) = concatMap flatten x
Now I wish to write my reverse function. The function is defined as:
myreverse :: NestedList a -> NestedList a
Which I think makes sense because I'm just rearranging the elements within the list.
I understand how to write a basic reverse function, and I also know that for Haskell's standard lists reverse is already defined.
My question is: how do I deal with the case where the head of the list is also a list? What I know needs to happen is that I reverse the head of the list and put it back onto the reverse of the tail. But how to achieve this?
why not this way
rev :: NestedList a -> NestedList a
rev (Elem a) = Elem a
rev (SubList xs) = SubList $ map rev $ reverse xs
if you add deriving (Show) to your data definition,
Prelude> rev $ SubList [Elem 1, SubList [Elem 2, Elem 3]]
SubList [SubList [Elem 3,Elem 2],Elem 1]
Prelude> rev $ SubList [Elem 1, SubList []]
SubList [SubList [],Elem 1]
Your nested list is actually a tree with elements at leavess:
SubList
/ \
SubList Elem 4
/ | \
Elem 1 Elem 2 Elem 3
So your myreverse would be a horizontal flip, i.e. recursive reverse of each list in SubList, as other answer points out.
The lesson here: Visualising data-structures helps to understand and implement actions on them.
Related
Here is an example
Examples:
- unnest;
val it = fn : 'a NestedList -> 'a list
(* [1,2,3] *)
- unnest(List [(Atom 1), (Atom 2), (Atom 3)]);
val it = [1,2,3] : int list
I was give
datatype 'a NestedList =
Nil
| Atom of 'a
| List of 'a NestedList list;
What I have so far
fun unnest(Nil) = []
| unnest(Atom(x)) = [x]
| unnest(List(x::xs)) = unnest(x);
which only gives the head part of the list and I do not know how to get to the rest of list.
I understand there is a way using concat and map and fn but is there without using library function?
Applying unnest to a NestedList value is meant to yield a plain old list. So we know the type of this function must be:
'a NestedList -> 'a list
When we apply unnest to a List, we need to recursively apply it to each element in that contained list.
There are two issues with your function.
It doesn't account for an empty list in the pattern-matching.
It only acts on the first item in a non-empty list.
If we map unnest to each element in that contained list, we'll get a list of lists. This isn't what we ultimately want, but we can work with it.
fun unnest(Nil) = []
| unnest(Atom(x)) = [x]
| unnest(List(lst)) = map unnest lst
The above won't compile because the final case yields an 'a list list. How can we turn a list of lists into just a list?
We can concatenate two lists with the # operator, and that means we can fold this over the lists to get a flattened list.
fun unnest(Nil) = []
| unnest(Atom(x)) = [x]
| unnest(List(lst)) = foldl op# [] (map unnest lst)
Evaluating unnest(List [(Atom 1), (Atom 2), (Atom 3)]) now gets us [3, 2, 1]. This is reversed because of the order in which foldl sends arguments to op#. If we write an anonymous function we can correct this.
fun unnest(Nil) = []
| unnest(Atom(x)) = [x]
| unnest(List(lst)) = foldl (fn (x, i) => i # x) [] (map unnest lst)
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]]
I am trying to get all combinations of a list. The result for [1,2,3] should be [(1,2),(1,3),(2,3)]. My implementation below, however, gives [(1,2),(2,3)].
parings [d] = []
parings (y:ys) = (y, head ys): parings ys
The list comprehension mentioned in 9000's answer can be trivially factored into a map call.
pairwise :: [a] -> [(a, a)]
pairwise [] = []
pairwise (x:xs) = map (\y -> (x, y)) xs ++ pairwise xs
Every list comprehension can be factored into some combination of map, filter, and concatMap, possibly with some let bindings interspersed. Doing so is a good exercise for learning how to manipulate functions.
Here is one implementation using tails from Data.List:
import Data.List
pairings :: [a] -> [(a, a)]
pairings = concatMap makePairs . tails
where
makePairs [] = []
makePairs (x:xs) = fmap ((,) x) xs
Notes:
I don't know whether tails counts as a "special import" for you -- though it is not in the Prelude, it can be found in the base library, which is always available.
To see what tails does, try tails [1..3].
((,) x) is just a compact way of writing (\y -> (x, y)). If you find it ugly, you can write the longer version instead, or enable the TupleSections extension and spell it as (x,).
makePairs might be written without explicit recursion as...
makePairs = maybe [] (\(x, xs) -> fmap ((,) x) xs) . uncons
... with uncons also being found in Data.List.
All the implementations in the answers here have a not insignificant problem: they retain consumed list segments in memory. To see what I'm talking about, watch the memory usage as you run head . drop 8000000 $ pairings [1..] in GHCi. I'm not confident about there being a workaround for that -- a simple concat . tails, for instance, appears to run into the same issue, while fmap makePairs . tails doesn't (even head . drop (10^9) . head . drop (10^9) . fmap makePairs . tails $ [1..] won't eat up all your memory).
I don't know why you're opposed to list comprehensions; with them, the solution is trivial:
pairwise :: [a] -> [(a, a)]
pairwise [] = []
pairwise (x:xs) = [(x, y) | y <- xs] ++ pairwise xs
You can factor out the comprehension into a separate function with explicit tail recursion if you want.
(The whole thing can be made tail-recursive, too, by keeping parameters for both sides of the ++ and having an accumulator parameter.)
I know how to use recursion to reverse a list, but I am trying to use foldl to make it more efficient. My code is as follow:
reverse list = foldl (++) [] (map (\x -> [x]) list)
When running it in GHCi, it returns the same list as input. What goes wrong? I also try to finish it by foldr but it does not show any change.
foldl passes the accumulator as the first argument to the function. ++ concatenates the first argument to the second, but, to reverse a list, you need to concatenate the second to the first. You can do this using flip (++):
Prelude> let reverse list = foldl (flip (++)) [] (map (\x -> [x]) list)
Prelude> reverse [1..5]
[5,4,3,2,1]
Instead of first converting all elements of the list to singleton lists (which is expensive as well), you can use the cons (:) function:
reverse :: Foldable t => t a -> [a]
reverse = foldl (flip (:)) []
So here we use flip (:) :: [a] -> a -> [a] as fold function. It takes a tail [a] and a head a, and constructs a list with the head as first element and the tail as last element.
So what happens is:
foldl (flip (:)) [] [1,4,2,5]
-> foldl (flip (:)) (1:[]) [4,2,5]
-> foldl (flip (:)) (4:1:[]) [2,5]
-> foldl (flip (:)) (2:4:1:[]) [5]
-> foldl (flip (:)) (5:2:4:1:[]) []
-> (5:2:4:1:[])
-> [5,2,4,1]
I'm kinda new to Haskell and I'm trying to generate all contiguous sublists of a list.
I current have the following:
listSublists :: [a] -> [[a]]
listSublists [] = [[]]
listSublists xs = [xs] ++ listSublists (init xs)
I know the function above would generate sublists with the last element removed but I've no idea how to finish my pseudocode.
My pseudocode is basically,
Take the whole complete list, remove tail. Pass xs of (x:xs) into
listSublists
For example, xs = [1,2,3]
[xs] ++ listSublists (init xs) would generate [1,2,3,4], [1,2,3], [1,2], [1], [] and I'm trying to continue that with passing in [2,3,4] as xs until the list is exhausted.
Can someone give me some pointers? Or am I thinking in a completely wrong way?
The listSublists function that you have is functionally almost identical to
the inits
function. You are on the right track, in that you can currently list all of
the prefixes of a given list.
What you want to ask is "what is a sublist of a list?" One answer is that it
is a suffix of a prefix of the list (i.e. chop off some portion from the
end of a list and then chop off some elements off the front of that list, and
you have one of the contiguous sublists).
So, if you have your prefixes, then what you want is a way to generate all
the suffixes of a given prefix (i.e. of some list). So, if you have
prefixes :: [a] -> [[a]]
prefixes [] = [[]]
prefixes xs = [xs] ++ prefixes (init xs)
you also want a corresponding function suffixes
suffixes :: [a] -> [[a]]
suffixes [] = [[]]
suffixes xs = [xs] ++ suffixes (??? xs)
I will leave it to you to figure out what to use for ???. With these two
functions, you then just take all the prefixes, and produce all the suffixes
to get all the contiguous sublists
allSublists :: [a] -> [[a]]
allSublists = concat . map suffixes . prefixes
You may want to remove all of the empty lists that will be in the result set,
as they are not that interesting of a case.
All sublists (not necessarily contiguous):
sublists [] = [[]]
sublists (x:xs) = [x:sublist | sublist <- sublists xs] ++ sublists xs
Only contiguous sublists:
nub $ concat $ map tails $ inits ls
or
(:) [] $ filter (\x -> length x /= 0) $ concat $ map tails $ inits ls