{-- EXTRA LIST COMPREHENSION ------------------------
note that i connects and continues in the second list generator.
[ (i,j) | i <- [1..3], j <-[i..3]] 
= 
  [(i,j)  | j <- [1..3]] ++
  [(2,j)  | j <- [2..3]] ++
  [(3,j)  | j <- [3..3]] ++
=
  [(1,1),(1,2),(1,3)] ++
  [(2,2),(2,3) ] ++
  [(3,3)] ++
= 
[(1,1),(1,2),(1,3),(2,2),(2,3),(3,3)]
--------------------------------------------
-- adding a filter
-------------------------------------------
[ (i,j) | i <- [1..3], j <-[1..3], i <= j ]
=
  [ (1,j) | j <- [1..3],1 <= j ] ++
  [ (2,j) | j <- [1..3],2 <= j ] ++
  [ (3,j) | j <- [1..3],3 <= j ]
=
  [(1,1)|1<=1]++[(1,2)|1<=2]++[(1,3)|1<=3]++
  [(2,1)|2<=1]++[(2,2)|2<=2]++[(1,3)|2<=3]++
  [(3,1)|3<=1]++[(3,2)|3<=2]++[(3,3)|3<=3]
=
  [(1,1)] ++ [(1,2)] ++ [(1,3)] ++
  []      ++ [(2,2)] ++ [(2,3)] ++
  []      ++ []      ++ [(3,3)]
=
[(1,1),(1,2),(1,3),(2,2),(2,3),(3,3)]

------------------------------------------
-- FORMAL DEFINITION FOR LIST COMPREHENSION
------------------------------------------
  q ::= x <- l, q | b, q | * 

[e | * ] -- empty
  = [e]  
[e | x <- [l1,...,ln],q] 
  = (let x = l1 in [e | q ]) ++ ... ++ (let x = ln in [e | q ]) 

[e | b, q ] 
  = if b then [ e | q ] else []

-----------------------------------------
-- HERE IT IS AS A PROGRAM
-----------------------------------------
in the lists comprhension they are either drawn from or filters 

[(i,j) | i <- [1..3], j <- [1..3], i <= j, * ]

----------------------------------------
-- the goal is to a capture a pattern that appears over and over and capture it in a single function.
----------------------------------------}
--       MAP -- FILTER -- FOLD -- 
----------------------------------------
-- TEMPLATE HASKELL is Meta Haskell which can alter/influence Haskell 

squares xs           = [ x*x | x <- xs]
squares xs           = [ x*x | x <- xs]
squares xs           = [ x*x | x <- xs]