fibs = 1:1:[x+y|x <- fibs, y <- tail fibs]
returns
[1,1,2,3,4,5,6,7,8,9]
fibs = 1:1:[x+y|(x, y) <- zip fibs (tail fibs)]
returns
[1,1,2,3,5,8,13,21,34,55...]
The first one is evaluating the Cartesian product (i.e. every combination) of fibs and tail fibs, while the second is evaluating the pairwise pairing.
Prelude> [(x,y) | x <- [1,2,3], y <- [4,5,6]]
[(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]
Prelude> [(x,y) | (x,y) <- [1,2,3] `zip` [4,5,6]]
[(1,4),(2,5),(3,6)]
Related
at the moment my code looks a bit like this:
gen (x:[]) = [[a] | a <- (someOp x)]
gen (x:y:[]) = [[a,b] | a <- (someOp x), b <- (someOp y)]
gen (x:y:z:[]) = [[a,b,c] | a <- (someOp x), b <- (someOp y), c <- (someOp z)]
...
and so on
is it possible to conclude the rest with gen(x:xs) ??
You can do this recursively:
gen [] = [[]]
gen (x:xs) = [ a:g | a <- someOp x, g <- gen xs ]
At each step you take all the lists generated by the previous step and combine each of them with every result of someOp.
You can verify that this degrades into your special cases by substitution.
For the function you here construct, a more generic function already exists: traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b). Your gen is equivalent to:
gen = traverse someOp
Suppose we have a list
x = [1..10]
and we intend to create another list y using this in this manner :
y= [a|a<-x]
So while creating the list y from x, it accesses each element of x( from 1 to 10) and inserts it in y in the same order. As a list in haskell is singly linked list, we can insert a new element only at its head. So first it inserts 1 to [] & we have [1]. Then it inserts 2 to its head & so we have [2,1]. Then it inserts 3 & we have [3,2,1] & so on. So ultimately we should get y as [10,9..1]. But instead we get y as [1..10]. Why is that so?
Because it "inserts" them at list's tail (while the list is being built), not head (cf. "tail recursion modulo cons"):
[a | a <- [1..10]] ==
[a | a <- (1:[2..10])] == -- [a | a <- ([1] ++ [2..10])]
1 : [a | a <- [2..10]] -- [1] ++ [a | a <- [2..10]]
This is because
[a | a <- (xs ++ ys)] == [a | a <- xs] ++ [a | a <- ys]
and
[a | a <- ys] == ys
The way you are thinking about list comprehensions is not quite correct. When you see a comprehension
y <- [f a | a <- x]
you shouldn't think about the successive result being added to the front of an (initially empty) result list.
Instead, think of each f a being added to the front of the result of running the list comprehension on the rest of x. That is,
[f a | a <- x:xs] == f x : [f a | a <- xs]
This is a recursive approach - by assuming that the result list exists for the tail of the list, you can add the next result to the front of it.
It's instructive to look at exactly how list comprehensions desugar to monadic computations, rather than use the intuition for how they work.
[a | a <- [1..3]] == do {a <- [1..3]; return a} -- desugared comprehension
== [1..3] >>= return a -- desugared do
== concat (map return [1..3]) -- definition of >>=
== concat [[1], [2], [3]] -- defintiion of return
== [1,2,3] -- definition of concat
I want to write a function that uses list comprehensions to generate a list of lists that works like this:
makeList 3 == [[1],[1,2],[1,2,3]]
makeList 5 == [[1],[1,2],[1,2,3],[1,2,3,4],[1,2,3,4,5]]
makeList (-2) == []
I end up with this solution, but It not gives me what it needs from the question obviously:
let makelist x = [x | x <- x, y <- [1..x]]
So if I enter this
Prelude> makelist [3]
the output will shows like this:
[3,3,3]
I wanted to be a list in list first then I want it to be increased. Thank you for help!
Let's try generating an inner list first, for some limit m:
> let inner m = [1..m]
> inner 5
[1,2,3,4,5]
Now, observe that your outer list, for some limit n, is [inner 1, inner 2, inner 3, ..., inner n], or, in list comprehension form:
> let outer n = [inner m | m <- [1..n]]
> outer 3
[[1], [1,2], [1,2,3]]
so we can combine the two into the single list comprehension expression:
> let makeList n = [[1..m] | m <- [1..n]]
> makeList 4
[[1],[1,2],[1,2,3],[1,2,3,4]]
I propose you this:
make_list n = [ [1..m] | m <- [1..n] ]
However there's something strange in your first attempt:
make_list x = [x | x <- x, y <- [1..x]]
there you put x for every purpose. It just feels wrong.
A recursive version based in list generation as well,
makeList' :: Int -> [[Int]]
makeList' n
| n < 1 = []
| otherwise = [1..n] : makeList' (n-1)
makeList :: Int -> [[Int]]
makeList n = reverse $ makeList' n
makeList' returns the desired outcome in reverse order.
I know you can define zipWith with zip as:
zipwith' f xs ys = [f x y | (x,y) <- zip xs ys]
But how about without zip? I read somewhere that you can do it with parallel list comprehension like this:
zipwith' f xs ys = [f x y | x <- xs | y <- ys]
But you have to add {-# LANGUAGE ParallelListComp #-} to the top of your code to make that work since it's an extension.
Are there any other ways of defining zipWith using list comprehension, preferably without helper functions or extensions?
Without zip you have to use some – arguably basic – list access functions, viz., drop and takeWhile. Both are built-in, so, not "helper functions" that you wanted to avoid:
zipW :: (a -> b -> c) -> [a] -> [b] -> [c]
zipW f xs ys = [z | [z] <- takeWhile (not.null)
[z | [z] <- takeWhile (not.null) -- ~ map (head.head)
[ [ [c | (c:_) <- [drop i r]] -- ~ take 1 . drop i
| (r:_) <- [drop i rs]] -- ~ take 1 . drop i
| let rs = [[f x y | y<- ys] | x<- xs], i <- [0..]]]]
This recovers the diagonal from the Cartesian product, taking care to handle the infinite lists (so, measuring their length is out of the question) as well as finite (so, !! can't be used).
~> zipW (,) [1..4] [10..]
[(1,10),(2,11),(3,12),(4,13)]
~> zipW (,) [1..] [10..13]
[(1,10),(2,11),(3,12),(4,13)]
And of course it is quadratic, as long as drop n is O(n), which it usually is.
If the lists are guaranteed to be infinite, it simplifies quite a bit into
zipWi f xs ys = [ rs !! i !! i | let rs = [[f x y | y<- ys] | x<- xs], i <- [0..]]
because using !! for list access is now okay (still quadratic, of course):
~> take 4 $ zipWi (,) [0..] [10..]
[(0,10),(1,11),(2,12),(3,13)]
To make it linear, the recursive solution can be encoded with unfoldr, iterate etc., but not with the list comprehensions, I think.
Hi I am a newbie in Haskell.
I am trying to do a simple task.
test :: (RealFloat a) => a -> a -> [a]
test xs ys= [ w : h: [] | w <- xs, h <- ys]
I am getting an error here. (with out a doubt)
In this task, I am simply trying to bind two lists (ex: test [12.12] [14.14])
and hopefully return a new combined list (ex: [12.12,14.14])
thanks for your help
Your signature is wrong. Try:
test xs ys = ...
then in ghci:
> :t test
test :: [t] -> [t] -> [[t]]
You need two arguments, both are lists, not two arguments of single elements.
Drakosha is correct. List concatenation already has an operator in Haskell.
test :: (RealFloat a) => [a] -> [a] -> [a]
test xs ys= xs ++ ys
You probably don't want to use a list comprehension here, unless you want to extract every element in your first and second list and do something with them. For example, a Cartesian Product:
list1 = [1.0,1.1,1.2] :: [Double]
list2 = [2.0,2.1,2.2] :: [Double]
testComps xs ys = [(x,y) | x <- xs, y <- ys]
Or addition:
testComps2 xs ys = [ x + y | x <- xs, y <- ys]
Or even creating lists:
testComps3 xs ys = [x : y : [] | x <- xs, y <- ys]
In GHCi, this will yield the following:
*Main> testComps list1 list2
[(1.0,2.0),(1.0,2.1),(1.0,2.2),(1.1,2.0),(1.1,2.1),(1.1,2.2),(1.2,2.0),(1.2,2.1)
,(1.2,2.2)]
*Main> testComps2 list1 list2
[3.0,3.1,3.2,3.1,3.2,3.3000000000000003,3.2,3.3,3.4000000000000004]
*Main> testComps3 list1 list2
[[1.0,2.0],[1.0,2.1],[1.0,2.2],[1.1,2.0],[1.1,2.1],[1.1,2.2],[1.2,2.0],[1.2,2.1]
,[1.2,2.2]]
The weird results in testComps2 is, of course, normal cruft when you're dealing with floating-point numbers. In the real world you'd compensate for this by rounding.
Another problem you'll run into is the difference between (++) and (:). Simply put, (:) tacks individual items onto a list, whereas (++) concatenates two lists.
You need list concatenation:
[12.12] ++ [14.14]
=> [12.12,14.14]