Haskell Nested List Comprehensions - list

I am studying for an exam and I am looking at an example of nested list comprehensions from the book "Learn you a Haskell", and I was hoping if anyone could explain me step by step how to analyze it and come out with its output.
let xxs = [[1,2,3],[2,3,4],[4,5]]
[ [ x | x <- xs, even x] | xs <- xxs ]]
Output: ([[2],[2,4],[4]])

[ [ x | x <- xs, even x] | xs <- xxs ]
[ [ x | x <- xs, even x] | xs <- [[1,2,3],[2,3,4],[4,5]] ]
[ [ x | x <- [1,2,3], even x] , [ x | x <- [2,3,4], even x] , [ x | x <- [4,5], even x] ]
[filter even [1,2,3], filter even [2,3,4], filter even [4,5]]
[[2],[2,4],[4]]
Or
[ [ x | x <- xs, even x] | xs <- xxs ]
map (\xs -> [ x | x <- xs, even x] ) xxs
map (\xs -> filter even xs) [[1,2,3],[2,3,4],[4,5]]
[filter even [1,2,3], filter even [2,3,4], filter even [4,5]]
[[2],[2,4],[4]]
Note this isn't the transformation that GHC actually does, just a way of writing it that might help you understand the output.

List comprehensions could have been defined by few identities:
[ f x | x <- [], ... ] === []
[ f x | x <- [y], ... ] === [ f y | {y/x}... ] -- well, actually, it's
-- case y of x -> [ f y | {y/x}... ] ; _ -> []
[ f x | x <- xs ++ ys, ...] === [ f x | x <- xs, ...] ++ [ f x | x <- ys, ...]
[ f x | True, ...] === [ f x | ... ]
[ f x | False, ...] === []
The handling of complex patterns (as opposed to simple variable patterns) is elided, only hinted at, for simplicity. {y/x}... means, y is substituted for x in .... For actual definition, see the Report.
It follows that
[ f x | xs <- xss, x <- xs] === concat [ [f x | x <- xs] | xs <- xss]
and
[ f x | x <- xs, test x ] === map f (filter test xs)
Your expression is equivalent to
[ [ x | x <- xs, even x] | xs <- xxs ] -- `]`, sic!
=
[ f xs | xs <- xxs ] where f xs = [ x | x <- xs, even x]
Which is to say, there's nothing special about a list comprehension being used as a value expression in the definition of f. It looks "nested", but actually, it isn't.
What is nested, are the generator expressions separated by commas:
[ x | xs <- xss, x <- xs ] === concat [ [x | x <- xs] | xs <- xss ]
-- ^^^ nested generator
(the equivalency like we saw above.) So then,
[ [ x | x <- xs, even x] | xs <- [[1,2,3],[2,3,4],[4,5]] ]
=
[ [ x | x <- [1,2,3], even x]] ++ [[ x | x <- [2,3,4], even x]] ++ [[ x | x <- [4,5], even x] ]
=
[ [ x | x <- [1,2,3], even x], [ x | x <- [2,3,4], even x], [ x | x <- [4,5], even x] ]
=
[ [ x | x <- [1], even x]++[ x | x <- [2], even x]++[ x | x <- [3], even x]
, [ x | x <- [2], even x]++[ x | x <- [3], even x]++[ x | x <- [4], even x]
, [ x | x <- [4], even x]++[ x | x <- [5], even x] ]
=
[ [ 1 | even 1]++[ 2 | even 2]++[ 3 | even 3]
, [ 2 | even 2]++[ 3 | even 3]++[ 4 | even 4]
, [ 4 | even 4]++[ 5 | even 5] ]
=
[ []++[ 2 ]++[], [ 2 ]++[]++[ 4 ], [ 4 ]++[] ]
=
[ [2], [2,4], [4] ]
Or, with filter if you'd prefer,
[ [ x | x <- [1,2,3], even x], [ x | x <- [2,3,4], even x], [ x | x <- [4,5], even x] ]
=
[ filter even [1,2,3], filter even [2,3,4], filter even [4,5] ]
=
[ [2], [2,4], [4] ]

Related

Prolog: Filter and list

Construct a predicate called fPairsAtoms/3 so that given an atom (first argument), and a list of pairs, unify a third parameter with the filtered list of pairs by selecting only the pairs that have the first component as the atom of the first argument.
Example:
fPairsAtoms(sA,[[basA,absAb],[ab,bbsA],[sA,abbsB],[bsA,sAsB],[sA,bb]],X)
Result:
X = [[sA,abbsB],[sA,bb]]
I do not understand ..... What should I face these types of exercises?
Can you help me find a solution?
Today I started with prolog, I am a newbie in every way.
If you've just started today, it probably is a bit too soon for you to tackle this problem.
First you should understand what Prolog terms are: atoms, logical Variables, compound terms foo(x,X,bar(baz)).
Then you should understand unification, a = a, a = A, A = a, A = foo(a), foo(A) = foo(a), [atom, B] = [A, bar].
You should understand lists representation, where
[ A, B, C ]
= [A, B | [C] ]
= [A | [B , C ]]
= [A | [B | [C] ]]
= ....
= [A , B , C | []]
so that unifying [A | B] = [a] succeeds, resulting in also unifying A = a and B = [], but unifying [A | B] = [] fails.
Then you need to understand predicates, which under procedural interpretation mean,
to_prove(This) :- need_to_prove(This) , and_also(That).
So that
fPairsAtoms(sA, [[basA,absAb],[ab,bbsA],[sA,abbsB],[bsA,sAsB],[sA,bb]], X) :-
X = [ [sA,abbsB], [sA,bb]].
is a perfectly valid, though exceedingly narrow, definition of one.
But then so are also
fPairsAtoms(sA, [[basA,absAb],[ab,bbsA],[sA,abbsB] | [[bsA,sAsB],[sA,bb]] ], X) :-
X = [ [sA,abbsB] | [ [sA,bb]] ].
% and
fPairsAtoms(sA, [ [ab,bbsA],[sA,abbsB] | [[bsA,sAsB],[sA,bb]] ], X) :-
X = [ [sA,abbsB] | [ [sA,bb]] ].
% and
fPairsAtoms(sA, [ [sA,abbsB] | [[bsA,sAsB],[sA,bb]] ], X) :-
X = [ [sA,abbsB] | [ [sA,bb]] ].
% and
fPairsAtoms(sA, [[bsA,sAsB],[sA,bb]] , Y) :-
Y = [ [sA,bb]].
% ... and
fPairsAtoms(sA, [] , Y) :-
Y = [].
and so also
fPairsAtoms(sA, [ [sA,abbsB] | L ], X) :-
L = [[bsA,sAsB],[sA,bb]],
Y = [ [sA,bb]],
X = [ [sA,abbsB] | Y ].
and thus
fPairsAtoms(sA, [ [sA,abbsB] | L ], X) :-
L = [[bsA,sAsB],[sA,bb]],
fPairsAtoms( L, Y),
Y = [ [sA,bb]],
X = [ [sA,abbsB] | Y ].
% and
fPairsAtoms(sA, [ [sA,abbsB] | L ], X) :-
L = [[bsA,sAsB],[sA,bb]],
fPairsAtoms( L, Y),
X = [ [sA,abbsB] | Y ].
% and
fPairsAtoms(sA, [ [sA,abbsB] | L ], X) :-
fPairsAtoms( L, Y),
X = [ [sA,abbsB] | Y ].
% and so
fPairsAtoms(sA, [ A | L ], X) :-
A = [sA, B ],
fPairsAtoms( L, Y),
X = [ A | Y ].
% and even
fPairsAtoms(SA, [ A | L ], X) :-
A = [SA, B ],
fPairsAtoms( SA, L, Y),
X = [ A | Y ].
But on the other hand, in cases were there was no match, we saw that it is
fPairsAtoms(SA, [ A | L ], X) :-
A = [SB, B ],
dif( SA, SB),
fPairsAtoms( SA, L, Y),
X = Y .
% i.e.
fPairsAtoms(SA, [ [SB, B ] | L ], X) :-
dif( SA, SB),
fPairsAtoms( SA, L, X) .
So which one of the two clauses, that we've ended up with,
fPairsAtoms( SA, [ [SA, _] | L ], X) :-
fPairsAtoms( SA, L, Y),
X = [A | Y].
fPairsAtoms( SA, [ [SB, _] | L ], X) :-
dif( SA, SB),
fPairsAtoms( SA, L, X).
is the right one? The answer is: both!
To filter the pairs in the list, you need to traverse it while comparing the given atom with the first element of each pair. A trivial predicate to traverse a list would be:
traverse([]).
traverse([Head| Tail]) :-
traverse(Tail).
The predicate in your problem description is terribly named and don't follow recommended Prolog coding guidelines. Let's rename it to filter_pairs_by_key/3 and change the argument order to filter_pairs_by_key(Pairs, SearchKey, FilteredPairs). Also, the recommended representation for a pair in Prolog is Key-Value. There are standard predicates and library predicates that expect this representation (e.g. keysort/2). Based on the traverse/2 predicate template and the code style recommendations, we can write:
filter_pairs_by_key([], _, []).
filter_pairs_by_key([Key-Value| Pairs], SearchKey, [Key-Value| FilteredPairs]) :-
Key = SearchKey,
filter_pairs_by_key(Pairs, Atom, FilteredPairs).
filter_pairs_by_key([Key-_| Pairs], SearchKey, FilteredPairs) :-
Key \= SearchKey,
filter_pairs_by_key(Pairs, SearchKey, FilteredPairs).
Note that I'm using two clauses for the non-empty list case: one when the pair key matches the atom and one when the match fails.
Sample call:
| ?- filter_pairs_by_key([basA-absAb,ab-bbsA,sA-abbsB,bsA-sAsB,sA-bb], sA, FilteredPairs).
FilteredPairs = [sA-abbsB,sA-bb] ?
yes
More can be said about this problem and this particular solution but, as mentioned in the comments, this is not a beginners exercise. Consider the comments recommendations and after being comfortable with Prolog list notation play with this solution.

Prolog - unifying two lists with/without variables

This Prolog code returns:
?- [a,b,c,d] = [a|[b,c,d]].
true
and this one
?- [X,Y] = [a|[b,c,d]].
returns false.
I am not totally grasping why [X, Y] is false. Trace is not helpful here. I would expect the following assignment to hold
X = a
Y = [b,c,d]
and the statement be true.
What does | do besides splitting on head and tail?
A list in Prolog is implemented as a linked list of functors. If you write a list like [a, b, c, d]. it looks in reality like:
+-------+
| (|)/2 |
+---+---+ +-------+
| o | o---->| (|)/2 |
+-|-+---+ +---+---+ +-------+
v | o | o---->| (|)/2 |
a +-|-+---+ +---+---+ +-------+
v | o | o---->| (|)/2 |
b +-|-+---+ +---+---+
v | o | o----> []
c +-|-+---+
v
d
or in Prolog notation [a | [b | c | [d | [] ] ] ]. The comma-separated list is syntactical sugar: if you write [a, b, c, d], the Prolog interpreter converts it to a representation as above.
Since [b, c, d] is equal to:
[ b | [ c | [ d | [] ] ] ]
and thus [ a | [b, c, d] ] is thus equal to
[a | [b | c | [d | [] ] ] ]
But the list [X, Y] is just equal to
[X, Y] == [ X | [ Y | [] ] ]
or in a structural way:
+-------+
| (|)/2 |
+---+---+ +-------+
| o | o---->| (|)/2 |
+-|-+---+ +---+---+
v | o | o----> []
X +-|-+---+
v
Y
If we then match it with [a | [b | c | [d | [] ] ] ] this means the "outer" shell can be matched, so X = a, but then Y = b, and [] = [ c | [ d | [] ] ]. The last part does not match, and thus it returns false. The X and Y are thus not the problem. The problem is that [] is a constant, and it does not match with the functor that represents [ c | [d] ].
If we would for example unify [ X | Y ] == [a, b, c, d] we get:
?- [ X | Y ] = [a, b, c, d].
X = a,
Y = [b, c, d].
So to conclude, one can say that | itself "does" nothing. It is a functor, just like f(1, 2). In Lisp they used cons [wiki] for this, and nil for the empty list. So [1, 4, 2, 5] looks in Lisp like cons 1 (cons 4 (cons 2 (cons 5 nil))), or in Prolog it would look like cons(1, cons(4, cons(2, cons(5, nil)))). It is only a bit cumbersome to write. In fact the comma separated notation is more the "magic" part. Prolog just performs unification for lists, just like it does for other functors and constants.

I need to combine all elements in a list using only prelude and no other modules in Haskell

n is the first argument, and a list is the second. The elements can be can selected several times and in different order.
So it will look something like:
com 1 [1,2,3] = [ [1], [2], [3] ]
com 2 [1,2,3] = [[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]]
Ive written these and they work but i need a general function
com :: Int -> [t] -> [[t]]
com x [] = []
com 1 ys = [[z]| z <- ys]
com 2 ys = [z:q:[] | z <- ys, q <- ys]
I think it will look something like this:
com x ys
| x < 0 = []
| otherwise qs = [ z:[] | z <- ys ] com (x-1) qs
all help appreciated
You started good:
com :: Int -> [t] -> [[t]]
com x [] = {- [] -} [[]] -- thanks to #cirdec for spotting this
com 1 ys = [ [z] | z <- ys]
com 2 ys = [ [z,q] | z <- ys, q <- ys] -- <<----
now continue with it for a while:
com 3 ys = [ [y,z,q] | y <- ys, z <- ys, q <- ys]
= [ y:[z,q] | y <- ys, z <- ys, q <- ys]
= [ y:[z,q] | y <- ys, [z,q] <- [ [z,q] | z <- ys, q <- ys]] -- <<----
= [ y:r2 | y <- ys, r2 <- [ [z,q] | z <- ys, q <- ys]] -- <<----
= [ y:r2 | y <- ys, r2 <- ...... ]
right? We can always replace equals by equals, in Haskell!
com 4 ys = [ [x,y,z,q] | x <- ys, y <- ys, z <- ys, q <- ys]
= [ x:[y,z,q] | x <- ys, y <- ys, z <- ys, q <- ys]
= ....
= [ x:r3 | x <- ys, r3 <- ...... ]
can you continue this? can you finish up this line of thought?
com n ys | n > 4 = [ x:r | x <- ys, r <- .... (n-1) .... ]

Is there a way to generate a series of list comprehensions programmatically in Haskell?

In my ongoing attempt to get better at Haskell, I'm attempting to solve a problem where I'd like to create a series of list comprehensions of this form:
m2 = [[x1,x2] | x1 <- [2..110], x2 <- [x1..111]]
m3 = [[x1,x2,x3] | x1 <- [2..22], x2 <- [x1..22], x3 <- [x2..24]]
m4 = [[x1,x2,x3,x4] | x1 <- [2..10], x2 <- [x1..10], x3 <- [x2..10], x4 <- [x3..12]]
...
Where x1 <= x2 ... <= xn, the number following m is the length of the sublists, and the first n - 1 terms are bounded by the same upper bound, while the nth term is bounded by some larger number.
I could certainly write all of it out by hand, but that's not particularly good practice. I'm wondering if there's a way to generate these lists up to a particular maximum m value. My immediate thought was Template Haskell, but I don't know enough about it to determine whether it's usable. Is there some other solution that's escaping me?
In pseudo-Haskell, what I'm looking for is some method that does something like:
mOfN n bound term = [ [x1..xn] | x1 <- [2..bound], x2 <- [x1..bound], ..., xn <- [x(n-1)..term] ]
The main issue is that I can't figure out how I would dynamically create x1,x2, etc.
Is this what you are looking for?
import Data.List (tails)
mofn 0 xs = [ [] ]
mofn m xs = [ y:zs | (y:ys) <- tails xs, zs <- mofn (m-1) ys ]
i.e. mofn 3 [1..5] is:
[[1,2,3],[1,2,4],[1,2,5],[1,3,4],[1,3,5],[1,4,5],[2,3,4],[2,3,5],[2,4,5],[3,4,5]]
The key is the tails function which returns successive tails of a list.
Update
Is this what you are looking for?
mofn' 1 lo hi bnd = [ [x] | x <- [lo..bnd] ]
mofn' k lo hi bnd = [ x:ys | x <- [lo..hi], ys <- mofn' (k-1) x hi bnd ]
mofn' 3 1 3 5 is:
[[1,1,1], [1,1,2], [1,1,3], [1,1,4], [1,1,5],
[1,2,2], [1,2,3], [1,2,4], [1,2,5],
[1,3,3], [1,3,4], [1,3,5],
[2,2,2], [2,2,3], [2,2,4], [2,2,5],
[2,3,3], [2,3,4], [2,3,5],
[3,3,3], [3,3,4], [3,3,5]
]

List appending in Haskell

So I wrote a function that takes a list of lists as an argument and takes every single element from the first list and appends it to a recursively called function on the list of lists' tail, in result returning all possible combinations of selecting elements from these lists.
foo :: [[a]] -> [[a]]
foo [] = [[]]
foo (x:xs) = [[(x !! a)] ++ b | a <- [0..length(x)-1], b <- foo xs]
*Main> foo [[1, 2], [3, 4], [5, 6]]
[[1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6]]
It indeed works how it should, but whenever I change the second line of my function to
foo [] = []
it always returns an empty list whenever I call it on a type-valid argument. What's the big deal?
with foo [] = [] the very last b <- foo xs will not be able to get anything when xs == [], because it wants to pull a b from nothing - so the list-comprehension will be empty.
with the foo [] = [[]] it will finally be b <- [[]] so b will get a single [].
remark
you can simplify this a bit (so you don't need the costly (!!)):
foo :: [[a]] -> [[a]]
foo [] = [[]]
foo (xs:xss) = [ y : ys | y <- xs, ys <- foo xss]
I think this is easier to read/explain too: take every x from xs and recursively combine it with every combination of the xss into a new list
what would go wrong with foo [] = []:
Let's test it with a simple case:
foo [[1],[2]]
= [ y:ys | y <- [1], ys <- foo [ [2] ] ]
= [ 1:ys | ys <- [ y':ys' | y' <- [2], ys' <- foo [] ] ]
= [ 1:ys | ys <- [ 2:ys' | ys' <- [] ] ]
= [ 1:ys | ys <- [] ]
= []
instead of (with foo [] = [[]]):
foo [[1],[2]]
= [ y:ys | y <- [1], ys <- foo [ [2] ] ]
= [ 1:ys | ys <- [ y':ys' | y' <- [2], ys' <- foo [] ] ]
= [ 1:ys | ys <- [ 2:ys' | ys' <- [[]] ] ]
= [ 1:ys | ys <- [ 2:[] ] ]
= [ 1:[2] ]
= [ [1,2] ]