How does the List monad work in this example? - list

The List monad has return x = [x]. So why in the following example is the result not [(["a", "b"], [2, 3])]?
> pairs a b = do { x <- a; y <- b; return (x, y)}
> pairs ["a", "b"] [2,3]
[("a",2),("a",3),("b",2),("b",3)]

Let us first analyze and rewrite the function pairs:
pairs a b = do { x <- a; y <- b; return (x, y)}
Here we thus have a monad. We use do as syntactical sugar. But the compiler rewrites this to:
pairs a b = a >>= (\x -> b >>= (\y -> return (x, y)))
Or in a more canonical form:
pairs a b = (>>=) a (\x -> (>>=) b (\y -> return (x, y)))
Now the list monad is defined as:
instance Monad [] where
return x = [x]
(>>=) xs f = concatMap f xs
So we have written:
pairs a b = concatMap (\x -> concatMap (\y -> [(x, y)]) b) a
So we thus take as input two lists a and b, and we perform a concatMap on a with as function (\x -> concatMap (\y -> [(x, y)]) b). In that function we perform another concatMap on b with as function \y -> [(x, y)].
So if we evaluate this with pairs ["a", "b"] [2,3] we get:
pairs ["a", "b"] [2,3]
-> concatMap (\x -> concatMap (\y -> [(x, y)]) [2,3]) ["a", "b"]
-> concatMap (\y -> [("a", y)]) [2,3] ++ concatMap (\y -> [("b", y)]) [2,3]
-> [("a", 2)] ++ [("a", 3)] ++ [("b", 2)] ++ [("b", 3)]
-> [("a", 2), ("a", 3), ("b", 2), ("b", 3)]

In general,
pairs a b = do { x <- a; y <- b; return (x, y) }
= do { x <- a;
do { y <- b;
do { return (x, y) }}}
means, in pseudocode,
pairs( a, b) { for x in a do:
for y in b do:
yield( (x, y) );
}
whatever the "for ... in ... do" and "yield" mean for the particular monad. More formally, it's
= a >>= (\x ->
do { y <- b; -- a >>= k ===
do { return (x, y) }}) -- join (k <$> a)
= join ( (<$> a) -- ( a :: m a
(\x -> -- k :: a -> m b
do { y <- b; -- k <$> a :: m (m b) )
do { return (x, y) }}) ) -- :: m b
( (<$>) is an alias for fmap).
For the Identity monad, where return a = Identity a and join (Identity (Identity a)) = Identity a, it is indeed
pairs( {Identity, a}, {Identity, b}) { x = a;
y = b;
yield( {Identity, {Pair, x, y}} );
}
For the list monad though, "for" means foreach, because return x = [x] and join xs = concat xs:
-- join :: m (m a) -> m a
-- join :: [] ([] a) -> [] a
-- join :: [[a]] -> [a]
join = concat
and so,
join [ [a1, a2, a3, ...],
[b1, b2, b3, ...],
.....
[z1, z2, z3, ...] ]
=
[ a1, a2, a3, ... ,
b1, b2, b3, ... ,
.....
z1, z2, z3, ... ]
Monadic bind satisfies ma >>= k = join (fmap k ma) where ma :: m a, k :: a -> m b for a Monad m. Thus for lists, where fmap = map, we have ma >>= k = join (fmap k ma) = concat (map k ma) = concatMap k ma:
m >>= k = [ a, = join [ k a, = join [ [ a1, a2, ... ], = [ a1, a2, ... ,
b, k b, [ b1, b2, ... ], b1, b2, ... ,
c, k c, [ c1, c2, ... ], c1, c2, ... ,
d, k d, [ d1, d2, ... ], d1, d2, ... ,
e, k e, [ e1, e2, ... ], e1, e2, ... ,
... ] >>= k ... ] ............... ] ........... ]
which is exactly what nested loops do. Thus
pairs ["a", -- for x in ["a", "b"] do:
"b"] [2, 3] -- for y in [2, 3] do:
= -- yield (x,y)
["a",
"b"] >>= (\x-> join (fmap (\y -> return (x,y)) [2, 3]) )
=
["a",
"b"] >>= (\x-> concat (map (\y -> [ (x,y) ]) [2, 3]) )
=
join [ "a" & (\x-> concat ((\y -> [ (x,y) ]) `map` [2, 3]) ), -- x & f = f x
"b" & (\x-> concat ((\y -> [ (x,y) ]) `map` [2, 3]) ) ]
=
join [ concat ((\y -> [ ("a",y) ]) `map` [2, 3]) ,
concat ((\y -> [ ("b",y) ]) `map` [2, 3]) ]
=
join [ concat [ [("a", 2)], [("a", 3)] ] , -- for y in [2, 3] do: yield ("a",y)
concat [ [("b", 2)], [("b", 3)] ] ] -- for y in [2, 3] do: yield ("b",y)
=
join [ [ ("a", 2) , ("a", 3) ] ,
[ ("b", 2) , ("b", 3) ] ]
=
[ ("a", 2) , ("a", 3) ,
("b", 2) , ("b", 3) ]
Loop unrolling is what nested loops do ⁄ are, and nested computations are the essence of Monad.
It is also interesting to notice that
join = = [a1] ++ = [a1] ++ join
[ [ a1, a2, ... ], [ a1, a2, ... ] ++ [a2, ... ] ++ [ [a2, ...],
[ b1, b2, ... ], [ b1, b2, ... ] ++ [ b1, b2, ... ] ++ [ b1, b2, ...],
[ c1, c2, ... ], [ c1, c2, ... ] ++ [ c1, c2, ... ] ++ [ c1, c2, ...],
[ d1, d2, ... ], [ d1, d2, ... ] ++ [ d1, d2, ... ] ++ [ d1, d2, ...],
[ e1, e2, ... ], [ e1, e2, ... ] ++ [ e1, e2, ... ] ++ [ e1, e2, ...],
............... ] ............... ............... .............. ]
which goes to the heart of the "nested loops ⁄ yield" analogy. Monads are higher order monoids, "what's the problem?"

Related

Haskell: Syntax for manipulating a list of lists

I am having trouble finding the correct syntax for manipulating a list of lists.
Here's what I have
> sumLsts :: [[a]] -> [[a]] -> [[a]]
> sumLsts [[]] [[]] = [[]]
> sumLsts [(x:xs):tx] [(y:ys):ty] = [((+) x y) : sumLsts xs ys] : sumLsts tx ty
Here's sample input and output
> sumLsts [[1,1,1], [1,10,20], [-3, -4, -2]] [[3,5,6],[2,3,4],[2,3,2]]
> [[4,6,7],[3,13,24],[-1,-1,0]]
I was thinking that [(x:xs):tx] would have (x:xs) be seen as a single list and tx be seen as the following list. Haskell doesn't seem to agree.
Here is the error message
Couldn't match expected type 'a' with actual type '[[a0]]'
'a' is a rigid type variable bound by
the type signature for:
sumLsts :: forall a. [[a]] -> [[a]] -> [[a]]
In the pattern: x : xs
In the pattern: (x : xs) : tx
In the pattern [(x : xs) : tx]
Relevant bindings include
sumLsts :: [[a]] -> [[a]] -> [[a]]
As is pointed out in the comments on the question, (x:xs) is the pattern for an object of type [a], whether the a there is Int, String, Bool, or even [a] itself like [Int].
In this case your pattern match should be:
sumLsts ((x:xs):tx) ((y:ys):ty) = ...
{- to [[1, 3, 6], [2, 4, 7], [3, 5, 8]], ((x:xs): tx) matches:
x = 1
xs = [3, 6]
tx = [[2, 4, 7], [3, 5, 8]]
-}
However do note that your function is just:
sumLsts = zipWith (zipWith (+))
zipWith pairs two lists together with a joining function, such that
zipWith f [x1, x2, ..., xn] [y1, y2, ..., yn] =
[ f x1 y1
, f x2 y2
, ...
, f xn yn ]
In this case, your outer two lists get paired together so each sublist is an x and y. You're trying to pair those together with addition, so f is another zipWith, this time zipWith (+)
zipWith (zipWith (+)) [[1,1,1], [1,10,20], [-3, -4, -2]] [[3,5,6],[2,3,4],[2,3,2]]
= [ [ 1, 1, 1] `zipWith (+)` [3, 5, 6]
, [ 1, 10, 20] `zipWith (+)` [2, 3, 4]
, [-3, -4, -2] `zipWith (+)` [2, 3, 2]]
= [ [ 1 + 3
, 1 + 5
, 1 + 6]
, [ 1 + 2
, 10 + 3
, 20 + 4]
, [ -3 + 2
, -4 + 3
, -2 + 2] ]

Is a function that unpacks lists possible?

I have the following problem, I want to write a function that generates nested lists and then unpacks the nested lists into a single list.
A function that generates nested lists of a dynamic degree depending on its arguments obviously does not type-check, as the return type would vary depending on the arguments. However is it possible to recursively unpack lists to always return a flat list?
Suppose the non-possible function would return this for an argument of 2:
[ [ [a], [b] ], [ [c], [d] ] ]
and this for an argument of 3:
[[[[a], [b], [c]], [[d], [e], [f]], [[g], [h], [i]]], [[[j], [k], [l]], [[m], [n], [o]], [[p], [q], [r]]], [[[s], [t], [u]], [[v], [w], [x]], [[y], [z], [a1]]]]
Now I would like to have some function that I can put into the recursive call that would result in something like this:
[ unpack [ unpack [a], unpack [b] ], unpack [ unpack [c], unpack [d] ] ]
which in turn would evaluate to [a, b, c, d]
I was able to write something like this for list of only one element:
unpack [x] = x
f 1 = [0]
f n = [unpack $ f x | x <- [1..n-1]]
*Main> f 3
[0,0]
But obviously it fails for 4:
*Main> f 4
[0,0,*** Exception: Non-exhaustive patterns in function unpack
Manual "trace":
f 3 = [unpack $ f x | x <- [1..3-1]]
= [ unpack $ f 1, unpack $ f 2]
= [ unpack [0], unpack [f x | x <- [1..2-1]]]
= [ unpack [0], unpack [f 1] ]
= [ unpack [0], unpack [0] ]
= [0, 0]
Is such a function theoretically possible? I have a strong feeling that not... but maybe that feeling is wrong.
If it has not become clear yet what I have in mind: This [unpack [1,2,3]] would result in the list [1,2,3].
As written in the comments, the program you want is not possible in Haskell.
Here's a possible alternative: Create a datatype
data Unpack a = Unpack [Unpack a] | Elem a
deriving (Eq, Ord)
Further you can write a function which evaluates the unpacking:
unpacked :: [Unpack a] -> [a]
unpacked [] = []
unpacked (Unpack x : xr) = unpacked x ++ unpacked xr
unpacked (Elem x : xr) = x : unpacked xr
Let's make the output prettier:
instance Show a => Show (Unpack a) where
show (Unpack xs) = show xs
show (Elem x) = show x
Example usage in ghci:
> list = [Unpack [Elem 1, Unpack [Elem 3, Elem 4]], Unpack [Elem 5, Elem 6, Elem 7]]
[[1,[3,4]],[5,6,7]]
> unpacked list
[1,3,4,5,6,7]

Prolog - Find sublists in order

I am currently using this in my Prolog program:
sublist(X, L) :- append(_, S, L), append(X, _, S).
It will correctly list the sublists of a list if I call it like so,
?- sublist(A, [1, 2, 3]).
A = [] ;
A = [1] ;
A = [1, 2] ;
A = [1, 2, 3] ;
A = [] ;
A = [2] ;
A = [2, 3] ;
A = [] ;
A = [3] ;
A = [] ;
false.
I am looking to make a new function that will try all the shorter substrings first, so that it will come up with something more like
[1] ; [2] ; [3] ; [1, 2] ; [2, 3] ; [1, 2, 3].
Taking out the empty lists isn't vital, but would be preferred.
How about one of the following? Using SWI-Prolog we define the following rules:
Version 1
sublist_of([X|Xs], [E|Es]) :-
append(Ruler, _, [E|Es]), % ensure we get answers in ascending lengths
same_length(Ruler, [X|Xs]),
append([_,[X|Xs],_], [E|Es]).
Version 2
sublist_of__ver2([X|Xs], [E|Es]) :-
append(Ruler, _, [E|Es]), % ensure we get answers in ascending lengths
same_length(Ruler, [X|Xs]),
append([_,[X|Xs],_], [E|Es]).
Version 3a
sublist_of__ver3a([X|Xs], [E|Es]) :-
len1_len2_len12([X|Xs], _, [E|Es]),
append([_,[X|Xs],_], [E|Es]).
len1_len2_len12([], Ys, Zs) :-
same_length(Ys, Zs).
len1_len2_len12([_|Xs], Ys, [_|Zs]) :-
len1_len2_len12(Xs, Ys, Zs).
Version 3b
sublist_of__ver3b(Xs, Es) :-
Xs = [_|_],
len1_len2_len12(Xs, _, Es),
append([_,Xs,_], Es).
Sample query as given by the OP:
?- sublist_of__ver2(Xs, [1,2,3,4]).
Xs = [1 ]
; Xs = [ 2 ]
; Xs = [ 3 ]
; Xs = [ 4]
; Xs = [1,2 ]
; Xs = [ 2,3 ]
; Xs = [ 3,4]
; Xs = [1,2,3 ]
; Xs = [ 2,3,4]
; Xs = [1,2,3,4]
; false.
I swapped arguments order, for readability - please forgive me :)
sublist(L, S) :-
length(L, N),
between(1, N, M),
length(S, M),
append([_,S,_], L).
yields
?- sublist([a,b,c],S).
S = [a] ;
S = [b] ;
S = [c] ;
S = [a, b] ;
S = [b, c] ;
S = [a, b, c] ;
false.
with Sicstus-prolog it's easy with sublist(?X,+List). inside library(lists3).
code
% sublist(?Sub, +List)
% is true when all members of Sub are members of List
:- sublist(?,+) is nondet.
sublist(List, List).
sublist(Sub, [Head|Tail]) :- sublist_(Tail, Head, Sub).
:- sublist_/3 is nondet.
sublist_(Sub, _, Sub).
sublist_([Head|Tail], _, Sub) :- sublist_(Tail, Head, Sub).
sublist_([Head|Tail], X, [X|Sub]) :- sublist_(Tail, Head, Sub).
result
?- sublist(Y,[1,2,3]).
Y = [1,2,3] ? ;
Y = [2,3] ? ;
Y = [3] ? ;
Y = [] ? ;
Y = [2] ? ;
Y = [1,3] ? ;
Y = [1] ? ;
Y = [1,2] ? ;
no

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] ]

Haskell - if else return clean tuple

My homework task is to group two tuples in a list if the second element of the first tuple is the same as the first element of the second tuple. Then, if the first tuple is (a, b) and the second is (b, c), the tuple (a, c) must be added to the result list.
I wrote first function wich takes element with one tuple and second list with many tuples and compare each to each.
this one works correcly:
c1 = ("a","x")
d1 = [ ("x","b"), ("z","c"), ("x","b"), ("z","c")
, ("x","b"), ("z","c"), ("x","b"), ("z","c") ]
getByOne c1 a1 = filter (/=[])
[ if (fst (last(take n a1))) == (snd c1)
then [((fst c1), (snd (last(take n a1))))]
else [] | n <- [1..(length a1) ] ]
output:
[ [("a","b")], [("a","b")], [("a","b")], [("a","b")] ]
But the problems is that I can't throw in if then and else statement just simple tuple, so I create a new list. In the end of this "workaround" i am getting list in list in list and so on. Also if output list was bigger, there were be more lists in lists.
Is there any way to pass out only tuple or empty tuple or i should somehow group theses lists ?
You can flatten the result using
concat :: [[a]] -> [a]
then you don't even need to filter (/=[]) - by the way, the condition (/= []) is more idiomatically written not . null, since the null test doesn't impose an Eq constraint on its argument (you already have one here, so it's just a matter of idiom).
Further, last (take n a1) is just the n-th element of a1 if 1 <= n <= length a1. Since you have that restriction imposed, that can more succinctly be expressed as a1 !! (n-1)
Then you have structurally
getByOne c1 a1 = concat $ [something c1 (a1 !! i) | i <- [0 .. length a1 - 1]]
(I have shifted indices to index by i), which is clearer and more efficiently expressed as
getByOne c1 a1 = concat $ map (something c1) a1
If you prefer a list comprehension to map, you can also write that as
getByOne c1 a1 = concat [something c1 x | x <- a1]
which in your case, using the ability to pattern-match in alist-comprehension generator, gives us
getByOne (f,s) a1 = concat [ if a == s then [(f,b)] else [] | (a,b) <- a1]
which is much shorter and more readable. Instead of using if condition then [element] else [] and concat, even nicer is to use a condition in the list comprehension,
getByOne (f,s) list = [(f,b) | (a,b) <- list, a == s]
which is short and clear.
[1..(length a1)] can be written [1 .. length a1]
[ if (fst (last(take n a1))) == (snd c1)
then [((fst c1), (snd (last(take n a1))))]
else [] | n <- [1..(length a1) ] ]
can be written
[ if fst lastElement == snd c1
then [(fst c1, snd lastElement)]
else [] | n <- [1 .. length a1 ]
, let lastElement = last (take n a1) ]
Then, instead of using the list index to go through it, use the list directly:
[ if x == snd c1
then [(fst c1, y)]
else [] | (x, y) <- a1 ]
Then, instead of using a list to represent the existence or not of a solution, use Maybe:
import Data.Maybe
c1 = ("a","x")
d1 = [ ("x","b"), ("z","c"), ("x","b"), ("z","c")
, ("x","b"), ("z","c"), ("x","b"), ("z","c") ]
getByOne c1 a1 = catMaybes
[ if x == snd c1
then Just (fst c1, y)
else Nothing | (x, y) <- a1 ]
Better yet, use a guard and get rid of the if then else:
getByOne (a, b) a1 = [ (a, d) | (c, d) <- a1
, b == c ]
Alternatively, if you want to use filter, you first filter the list of matching tuples, then build the corresponding results with map:
getByOne (a, b) a1 = map (\(_, c) -> (a, c))
. filter (\(c, _) -> b == c)
$ a1
which simplifies into
getByOne (a, b) = map (\(_, c) -> (a, c))
. filter (\(c, _) -> b == c)