Haskell - how to count elements in nested list - list

Lets say I have nested lsit: [1, [2, 3, 4], [5, [6]]] and I want to count how many elements it has. In this case it is six elements. I have written such code for doing this:
totalElems :: [a] -> Int
totalElems (x:xs) = case (x, xs) of
(_, []) -> 0
(y:ys, _) -> 1 + totalElems ys + totalElems xs
(_, _) -> 1 + totalElems xs
But I've got an error:
a.hs:4:42:
Couldn't match expected type ‘a’ with actual type ‘[a0]’
‘a’ is a rigid type variable bound by
the type signature for totalElems :: [a] -> Int at a.hs:1:15
Relevant bindings include
xs :: [a] (bound at a.hs:2:15)
x :: a (bound at a.hs:2:13)
totalElems :: [a] -> Int (bound at a.hs:2:1)
In the pattern: y : ys
In the pattern: (y : ys, _)
In a case alternative:
(y : ys, _) -> 1 + totalElems ys + totalElems xs
How I can do this in Haskell?

You can't make freeform lists-within-lists like that in Haskell. Dynamically typed langues will tolerate silliness like that, but strongly-typed Haskell won't.
1 is of type Int, and [2,3,4] is of a different type [Int]. Things in a list have to be of the same type.
However, you could do something like this:
data Nest a = Elem a | List [Nest a]
example ::Nest Int
example = List [Elem 1, List [Elem 2, Elem 3, Elem 4], List [Elem 5, List [Elem 6]]]
countNest :: Nest a -> Int
countNest (Elem x) = 1
countNest (List xs) = sum $ map countNest xs

Let's say I have nested lsit: [1, [2, 3, 4], [5, [6]]]
You can't have that list. It won't type-check. Try typing it by itself in GHCi; it'll just spit an error message at you. Since this input can't exist in the first place, trying to write a function to process it is a doomed endeavor.
Instead, you need to define a custom data type for this. See the other answers.

As others have said, the simplest way to do this is with a different data structure, like the tree NovaDenizen defined. However, just so you know, Haskell's type system enables various ways of creating "lists" in which the elements have different types : see https://wiki.haskell.org/Heterogenous_collections

Related

Concatenating 2 inputted lists in Haskell

I'm trying to combine 2 lists from input but I am getting an error every time.
Here is my code:
myAppend :: [a] -> [a] -> [a]
myAppend a b = zipWith (+) a b
Getting this error:
"No instance for (Num a) arising from a use of ‘+’"
I was given this solution but it doesn't really make sense to me
myAppend :: [a] -> [a] -> [a]
myAppend [] xs = xs
myAppend (y:ys) xs = y:(myAppend ys xs)
I don't really understand the second and third line.
Can anyone help?
Thanks
Your myAppend does not concatenate two lists, it aims to sum elementwise the two lists, so myAppend [1,4,2,5] [1,3,0,2] will produce [2,7,2,7]. It will require a Num a constraint, since it can only work if the elements of the lists are Numbers:
myAppend :: Num a => [a] -> [a] -> [a]
myAppend a b = zipWith (+) a b
As for the solution here it uses recursion. Lists in Haskell are like linked lists: you have a an empty list ("nil") which is represented by the [] data constructor, and a node ("cons") which is represented with (x:xs) where x points to the first item, and xs points to the list of remaining elements. So [1,4,2,5] is short for (1:(4:(2:(5:[])))).
If we want to append [1,4] and [2,5] we thus want to produce a list (1:(4:(2:(5:[])))) out of (1:(4:[])) and (2:(5:[])). This means we create a linked list with all the elements of the first list, but instead of pointing to the empty list [], we let it point to the second list for the remaining elements. We do this through recursion:
myAppend (y:ys) xs = y : myAppend ys xs
will match if the first list unifies with the (y:ys) pattern. In that case we thus produce a list with y as first element, and the result of myAppend ys xs as as list of remaining elements ("tail"). Eventually we will thus call myAppend ys xs with the empty list [] as first item. In that case, we thus return the second list instead of the empty list, to append the second list to it.
We thus make calls that look like:
myAppend [1, 4] [2, 5]
= myAppend (1:(4:[])) (2:(5:[]))
-> 1 : (myAppend (4:[]) (2:(5:[])))
-> 1 : (4 : (myAppend [] (2:(5:[]))))
-> 1 : (4 : (2:(5:[]))
= [1, 4, 2, 5]

Creating a list of all possible lists, given each element can take one of n values

In Haskell I'm trying to create a function with the typing Int -> [a] -> [[a]], that generates a list such as: [[0, 0], [0, 1], [1, 0], [1, 1]] where each element in the smaller lists can take the value of either 1 or 0. Each of the smaller lists has the same size, which in this case is 2. If the size of the smaller lists was 3, I would expect to get the output [[0,0,0], [0,0,1], [0,1,0], [1,0,0], [1,1,0], [0,1,1], [1,0,1], [1,1,1]]
I've looked in to the permutations function, but this does not achieve exactly what I want. I believe there is also a variate function, but I cannot access this library.
Rather than the exact function (which would also be useful), what would be the process to generate such a list?
As oisdk mentions in a comment, a more general version of this exact function is already defined, with the name Control.Monad.replicateM:
Prelude> import Control.Monad (replicateM)
Prelude Control.Monad> replicateM 3 [0,1]
[[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]]
We can use the list monad for this:
example :: [[Int]]
example = do
x <- [0,1]
y <- [0,1]
pure [x,y]
ghci> example
[[0,0],[0,1],[1,0],[1,1]]
Play with this. Then you should be able to combine it with recursion on n to create the function you need.
I'm not sure I understood the specification, but from the examples, one possible definition is
lists :: Int -> [[Int]]
lists 0 = [[]]
lists n = map (0:) xss ++ map (1:) xss
where xss = lists (n-1)
-- λ> lists 2
-- [[0,0],[0,1],[1,0],[1,1]]
-- λ> lists 3
-- [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]]
Another definition, using comprehension instead of map, is
lists :: Int -> [[Int]]
lists 0 = [[]]
lists n = [x:xs | x <- [0,1], xs <- lists (n-1)]
-- λ> lists 2
-- [[0,0],[0,1],[1,0],[1,1]]
-- λ> lists 3
-- [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]]
You can use the sequence function.
Like this:
λ>
λ> :t sequence
sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
λ>
λ> let { allLists :: Int -> [a] -> [[a]] ; allLists n xs = sequence $ replicate n xs ; }
λ>
λ> allLists 3 [0,1]
[[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]]
λ>

List of lists, take next element

I have [[Integer]] -> [Integer] and want to take the first element of the first sub-list, the second element of the second sub-list and .. the n-th element of the n-th sub-list and so on.
I am trying to achieve this using list comprehensions. However, I first drop an incrementing number of elements and the take the head of the remaining. But there again I don't know how to use drop (inc z) where z = 0 with inc c = c + 1 as an already defined function, in presumably this:
getNext :: [[Integer]] -> [Integer]
getNext xs = [y | drop (inc z) (y:ys) <- xs, (y:_) <- xs]
where z = 0
I know that the code above is not working, but again I had only so far come up to this and hit a wall.
You can do it like this:
getNext :: [[a]] -> [a]
getNext xs = [ head $ drop y x | (x,y) <- zip xs [0..]]
Although note that this function is partial because of head.
As the other answers suggest, you can use a zip function and zip with the list of indices.
The Glasgow Haskell Compiler (GHC) however offers the Parallel List Comp extension:
{-# LANGUAGE ParallelListComp #-}
diagonal :: [[a]] -> [a]
diagonal ls = [l !! i | l <- ls | i <- [0..]]
The (!!) operator gets the i-th element from a list.
Furthermore it is always advisable to use the most generic function signature; so [[a]] -> [a] instead of [[Integer]] -> [Integer]. This can be useful if you later decide to take the diagonal of a matrix of Double's, String, lists, custom types,...
You can zip the actual list of list of integers and another list which runs from 0 to infinity and get the corresponding elements, like this
picker :: [[Integer]] -> [Integer]
picker xs = [(x !! y) | (x, y) <- (zip xs [0..])]
main = print $ picker [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
-- [1,5,9]
The expression [0..] will create an infinite list, lazily, starting from 0 and we zip it with xs. So, on every iteration, the result of zip would be used like this
[1, 2, 3] !! 0
[4, 5, 6] !! 1
[7, 8, 9] !! 2
We get element at index 0, which is 1, on the first iteration and 5 and 9 on the following iterations.

groupBy with multiple test functions

Is there a better and more concise way to write the following code in Haskell? I've tried using if..else but that is getting less readable than the following. I want to avoid traversing the xs list (which is huge!) 8 times to just separate the elements into 8 groups. groupBy from Data.List takes only one test condition function: (a -> a -> Bool) -> [a] -> [[a]].
x1 = filter (check condition1) xs
x2 = filter (check condition2) xs
x3 = filter (check condition3) xs
x4 = filter (check condition4) xs
x5 = filter (check condition5) xs
x6 = filter (check condition6) xs
x7 = filter (check condition7) xs
x8 = filter (check condition8) xs
results = [x1,x2,x3,x4,x5,x6,x7,x8]
This only traverses the list once:
import Data.Functor
import Control.Monad
filterN :: [a -> Bool] -> [a] -> [[a]]
filterN ps =
map catMaybes . transpose .
map (\x -> map (\p -> x <$ guard (p x)) ps)
For each element of the list, the map produces a list of Maybes, each Maybe corresponding to one of the predicates; it is Nothing if the element does not satisfy the predicate, or Just x if it does satisfy the predicate. Then, the transpose shuffles all these lists so that the list is organised by predicate, rather than by element, and the map catMaybes discards the entries for elements that did not satisfy a predicate.
Some explanation: x <$ m is fmap (const x) m, and for Maybe, guard b is if b then Just () else Nothing, so x <$ guard b is if b then Just x else Nothing.
The map could also be written as map (\x -> [x <$ guard (p x) | p <- ps]).
If you insist on one traversing the list only once, you can write
filterMulti :: [a -> Bool] -> [a] -> [[a]]
filterMulti fs xs = go (reverse xs) (repeat []) where
go [] acc = acc
go (y:ys) acc = go ys $ zipWith (\f a -> if f y then y:a else a) fs acc
map (\ cond -> filter (check cond) xs) [condition1, condition2, ..., condition8]
I think you could use groupWith from GHC.Exts.
If you write the a -> b function to assign every element in xs its 'class', I belive groupWith would split xs just the way you want it to, traversing the list just once.
groupBy doesn't really do what you're wanting; even if it did accept multiple predicate functions, it doesn't do any filtering on the list. It just groups together contiguous runs of list elements that satisfy some condition. Even if your filter conditions, when combined, cover all of the elements in the supplied list, this is still a different operation. For instance, groupBy won't modify the order of the list elements, nor will it have the possibility of including a given element more than once in the result, while your operation can do both of those things.
This function will do what you're looking for:
import Control.Applicative
filterMulti :: [a -> Bool] -> [a] -> [[a]]
filterMulti ps as = filter <$> ps <*> pure as
As an example:
> filterMulti [(<2), (>=5)] [2, 5, 1, -2, 5, 1, 7, 3, -20, 76, 8]
[[1, -2, 1, -20], [5, 5, 7, 76, 8]]
As an addendum to nietaki's answer (this should be a comment but it's too long, so if his answer is correct, accept his!), the function a -> b could be written as a series of nested if ... then .. else, but that is not very idiomatic Haskell and not very extensible. This might be slightly better:
import Data.List (elemIndex)
import GHC.Exts (groupWith)
f xs = groupWith test xs
where test x = elemIndex . map ($ x) $ [condition1, ..., condition8]
It categorises each element by the first condition_ it satisfies (and puts those that don't satisfy any into their own category).
(The documentation for elemIndex is here.)
The first function will return a list of "uppdated" lists and the second function will go through the whole list and for each value uppdate the list
myfilter :: a -> [a -> Bool] -> [[a]] -> [[a]]
myfilter _ [] [] = []
myfilter x f:fs l:ls | f x = (x:l): Myfilter x fs ls
| otherwise = l:Myfilter x fs ls
filterall :: [a] -> [a -> Bool] -> [[a]] -> [[a]]
filterall [] _ l = l
filterall x:xs fl l:ls = filterall xs fl (myfilter x fl l)
This should be called with filterall xs [condition1,condition2...] [[],[]...]

How can I build a list from another list, creating multiple elements for each element in the original list?

I want to do something like
[(x, y, x+y) | (x,y) <- original]
But of course, this will return something like:
[(0, 0, 0), (0, 1, 1), (1, 1, 2)]
What I want is something like:
[0, 0, 0, 0, 1, 1, 1, 1, 2]
I am quite new to Haskell, and unfamiliar with its idioms. How can I accomplish this in Haskell?
First, a diatribe on types. You are drawing the pair (x,y) from a list named original. Original must be a list of pairs, original :: [(a,b)], such as [(1,6), (4,9)]. You then construct a tuple for each element, hence your result of a list of tuples. I am going by the guess that you never wanted any tuples but actually want some number of elements of the list to be combined by your function and concatenate the results into a new list.
You might looking for the concatMap function:
> :t concatMap
concatMap :: (a -> [b]) -> [a] -> [b]
> concatMap (\x -> [x,x+1,x+7]) [1,2,3]
[1,2,8,2,3,9,3,4,10]
If you actually want to consume two (or more) elements at once then there are a few missing details, such as what to do if you have an odd number of elements and weather or not elements repeat (so you see [1,2,3] as two inputs 1,2 and 2,3).
If elements repeat then this is just a concatMap and a zip:
> let ls = [1,2,3] in concatMap (\(x,y) -> [x,y,x+y]) (zip ls (drop 1 ls))
[1,2,3,2,3,5]
But if you want to see them as [1,2] and [3] then you're best off writing your own function:
func [] = []
func [x] = [[x]] -- What do you want with the odd remaining element?
func (x:y:rest) = [x,y,x+y] : func rest
> concat (func [1,2,3])
[1,2,3,3]
Looks like you're just making a non-deterministic choice -- just what list comprehensions were made for!
[v | (x,y) <- original, v <- [x, y, x+y]]
You can for example create a list of lists and then use concat to flatten it.
concat [[x, y, x+y] | (x, y) <- original]