Choose increasing sequence from a list - list

I would like to ask how to choose increasing subsequence of elements from a list in Haskell. The rule is that in a not empty list the first element is chosen and then every element that is bigger than the previously chosen element. For example in a list [3,1,8,4,6,7,9,2,11,4,3]
would be chosen sublist [3,8,9,11].
My code so far doesn't cover the problem completely:
incrSub :: Ord a => [a] -> [a]
incrSub [] = []
incrSub (x:xs) = if x < head xs then x: incrSub (xs) else incrSub (xs)

Consider the evaluation of your function on the provided sample input:
incrSub [3, 1, 8, 4, 6, 7, 9, 2, 11, 4, 3]
incrSub (3 : 1 : 8 : 4 : 6 : 7 : 9 : 2 : 11 : 4 : 3 : [])
3 < 1 == False → incrSub (1 : 8 : 4 : 6 : 7 : 9 : 2 : 11 : 4 : 3 : [])
1 < 8 == True → 1 : incrSub (8 : 4 : 6 : 7 : 9 : 2 : 11 : 4 : 3 : [])
8 < 4 == False → 1 : incrSub (4 : 6 : 7 : 9 : 2 : 11 : 4 : 3 : [])
4 < 6 == True → 1 : 4 : incrSub (6 : 7 : 9 : 2 : 11 : 4 : 3 : [])
6 < 7 == True → 1 : 4 : 6 : incrSub (7 : 9 : 2 : 11 : 4 : 3 : [])
7 < 9 == True → 1 : 4 : 6 : 7 : incrSub (9 : 2 : 11 : 4 : 3 : [])
9 < 2 == False → 1 : 4 : 6 : 7 : incrSub (2 : 11 : 4 : 3 : [])
2 < 11 == True → 1 : 4 : 6 : 7 : 2 : incrSub (11 : 4 : 3 : [])
11 < 4 == False → 1 : 4 : 6 : 7 : 2 : incrSub (4 : 3 : [])
4 < 3 == False → 1 : 4 : 6 : 7 : 2 : incrSub (3 : [])
3 < undefined == undefined → 1 : 4 : 6 : 7 : 2 : undefined
Notice the relationship between the actual result and the expected result:
input 3 : 1 : 8 : 4 : 6 : 7 : 9 : 2 : 11 : 4 : 3 : []
expected 3 : 8 : 9 : 11 : []
actual 1 : 4 : 6 : 7 : 2 : undefined
So this suggests a few things to look at:
Your condition is filtering the opposite of what you intended.
You are not handling the end of the list correctly. In particular, consider the case of a 1-element list incrSub [42].
Your code is prone to errors because you’re using head, which is a partial function. Preferring pattern-matching may help, especially if you enable warnings (e.g. passing -Wall to GHC or adding {-# GHC_OPTIONS -Wall #-} to your file). Recall that you can use nested patterns like x1 : x2 : xs to match a list of at least 2 elements x1 and x2.
Working through examples like this using equational reasoning is a very powerful debugging technique for Haskell code. You can also use property-based testing libraries like QuickCheck to identify test cases that fail. For example, it quickly identifies the minimal failing test case of singleton lists:
> import Test.QuickCheck (quickCheck)
> resultIsSorted :: [Int] -> Bool; resultIsSorted input = let { result = incrSub input } in result == sort result
> quickCheck resultIsSorted
*** Failed! Exception: 'Prelude.head: empty list' (after 2 tests and 2 shrinks):
[0]
You can write more complex properties to find more interesting edge cases.

Related

Manual iteration through 2D vector of group nodes

I have stored a directed graph in a 2D vector and I want to iterate through all the possible path from any directed graph going from left to right via groups in a recursive manner. I have given an example below and want to iterate through all the paths from the first group (in this example G1) to any last group (in this example G3). I have been trying a lot but I'm not able to build a recursive to iterate through all the paths with any amount of groups. So I need help with building a manual iteration system/algorithm of loops without recursion function calls. For the iteration part, if I can get an algorithm which can print all the possible paths, it will be more than helpful. So, any source, tips and tricks will be useful. Thanks.
graph:
script.cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> map = {
{ 1, 2 },
{ 3, 4, 5 },
{ 6, 7 }
};
// Print all paths
// Note :- every array in the map is a group
return 0;
}
output:
1 -> 3 -> 6
1 -> 3 -> 7
1 -> 4 -> 6
1 -> 4 -> 7
1 -> 5 -> 6
1 -> 5 -> 7
2 -> 3 -> 6
2 -> 3 -> 7
2 -> 4 -> 6
2 -> 4 -> 7
2 -> 5 -> 6
2 -> 5 -> 7
#Compile using g++ -std=c++11 code.cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<vector<int> > map = {
{ 1, 2 },
{ 3, 4, 5 },
{ 6, 7 }
};
vector<int> sizes(map.size());
vector<int> indexes(map.size());
int combinations = 1;
for(int i=0; i<map.size();i++){
sizes[i]=map[i].size();
}
for(int i=0; i<map.size();i++){
combinations*=map[i].size();
}
for(int combination=1; combination <= combinations; combination++){
int multiple = 1;
for(int ind=0; ind<indexes.size(); ind++){
cout << map[ind][indexes[ind]];
if(ind < indexes.size()-1)
cout << " -> ";
}
cout << endl;
for(int j=map.size()-1;j>=0;j--){
multiple*=map[j].size();
indexes[map.size()-1]=combination % map[map.size()-1].size();
if(combination % multiple == 0 && j>0){
//cout << "*";
indexes[j-1] = (indexes[j-1]+1)%map[j-1].size();
}
}
}
return 0;
}
vector<vector<int> > map = {
{ 1, 2 },
{ 3, 4, 5, 10, 100 },
{ 6, 7, 8 },
{ 6, 7 },
{ 600, 17 }
};
1 -> 3 -> 6 -> 6 -> 600
1 -> 3 -> 6 -> 6 -> 17
1 -> 3 -> 6 -> 7 -> 600
1 -> 3 -> 6 -> 7 -> 17
1 -> 3 -> 7 -> 6 -> 600
1 -> 3 -> 7 -> 6 -> 17
1 -> 3 -> 7 -> 7 -> 600
1 -> 3 -> 7 -> 7 -> 17
1 -> 3 -> 8 -> 6 -> 600
1 -> 3 -> 8 -> 6 -> 17
1 -> 3 -> 8 -> 7 -> 600
1 -> 3 -> 8 -> 7 -> 17
1 -> 4 -> 6 -> 6 -> 600
1 -> 4 -> 6 -> 6 -> 17
1 -> 4 -> 6 -> 7 -> 600
1 -> 4 -> 6 -> 7 -> 17
1 -> 4 -> 7 -> 6 -> 600
1 -> 4 -> 7 -> 6 -> 17
1 -> 4 -> 7 -> 7 -> 600
1 -> 4 -> 7 -> 7 -> 17
1 -> 4 -> 8 -> 6 -> 600
1 -> 4 -> 8 -> 6 -> 17
1 -> 4 -> 8 -> 7 -> 600
1 -> 4 -> 8 -> 7 -> 17
1 -> 5 -> 6 -> 6 -> 600
1 -> 5 -> 6 -> 6 -> 17
1 -> 5 -> 6 -> 7 -> 600
1 -> 5 -> 6 -> 7 -> 17
1 -> 5 -> 7 -> 6 -> 600
1 -> 5 -> 7 -> 6 -> 17
1 -> 5 -> 7 -> 7 -> 600
1 -> 5 -> 7 -> 7 -> 17
1 -> 5 -> 8 -> 6 -> 600
1 -> 5 -> 8 -> 6 -> 17
1 -> 5 -> 8 -> 7 -> 600
1 -> 5 -> 8 -> 7 -> 17
1 -> 10 -> 6 -> 6 -> 600
1 -> 10 -> 6 -> 6 -> 17
1 -> 10 -> 6 -> 7 -> 600
1 -> 10 -> 6 -> 7 -> 17
1 -> 10 -> 7 -> 6 -> 600
1 -> 10 -> 7 -> 6 -> 17
1 -> 10 -> 7 -> 7 -> 600
1 -> 10 -> 7 -> 7 -> 17
1 -> 10 -> 8 -> 6 -> 600
1 -> 10 -> 8 -> 6 -> 17
1 -> 10 -> 8 -> 7 -> 600
1 -> 10 -> 8 -> 7 -> 17
1 -> 100 -> 6 -> 6 -> 600
1 -> 100 -> 6 -> 6 -> 17
1 -> 100 -> 6 -> 7 -> 600
1 -> 100 -> 6 -> 7 -> 17
1 -> 100 -> 7 -> 6 -> 600
1 -> 100 -> 7 -> 6 -> 17
1 -> 100 -> 7 -> 7 -> 600
1 -> 100 -> 7 -> 7 -> 17
1 -> 100 -> 8 -> 6 -> 600
1 -> 100 -> 8 -> 6 -> 17
1 -> 100 -> 8 -> 7 -> 600
1 -> 100 -> 8 -> 7 -> 17
2 -> 3 -> 6 -> 6 -> 600
2 -> 3 -> 6 -> 6 -> 17
2 -> 3 -> 6 -> 7 -> 600
2 -> 3 -> 6 -> 7 -> 17
2 -> 3 -> 7 -> 6 -> 600
2 -> 3 -> 7 -> 6 -> 17
2 -> 3 -> 7 -> 7 -> 600
2 -> 3 -> 7 -> 7 -> 17
2 -> 3 -> 8 -> 6 -> 600
2 -> 3 -> 8 -> 6 -> 17
2 -> 3 -> 8 -> 7 -> 600
2 -> 3 -> 8 -> 7 -> 17
2 -> 4 -> 6 -> 6 -> 600
2 -> 4 -> 6 -> 6 -> 17
2 -> 4 -> 6 -> 7 -> 600
2 -> 4 -> 6 -> 7 -> 17
2 -> 4 -> 7 -> 6 -> 600
2 -> 4 -> 7 -> 6 -> 17
2 -> 4 -> 7 -> 7 -> 600
2 -> 4 -> 7 -> 7 -> 17
2 -> 4 -> 8 -> 6 -> 600
2 -> 4 -> 8 -> 6 -> 17
2 -> 4 -> 8 -> 7 -> 600
2 -> 4 -> 8 -> 7 -> 17
2 -> 5 -> 6 -> 6 -> 600
2 -> 5 -> 6 -> 6 -> 17
2 -> 5 -> 6 -> 7 -> 600
2 -> 5 -> 6 -> 7 -> 17
2 -> 5 -> 7 -> 6 -> 600
2 -> 5 -> 7 -> 6 -> 17
2 -> 5 -> 7 -> 7 -> 600
2 -> 5 -> 7 -> 7 -> 17
2 -> 5 -> 8 -> 6 -> 600
2 -> 5 -> 8 -> 6 -> 17
2 -> 5 -> 8 -> 7 -> 600
2 -> 5 -> 8 -> 7 -> 17
2 -> 10 -> 6 -> 6 -> 600
2 -> 10 -> 6 -> 6 -> 17
2 -> 10 -> 6 -> 7 -> 600
2 -> 10 -> 6 -> 7 -> 17
2 -> 10 -> 7 -> 6 -> 600
2 -> 10 -> 7 -> 6 -> 17
2 -> 10 -> 7 -> 7 -> 600
2 -> 10 -> 7 -> 7 -> 17
2 -> 10 -> 8 -> 6 -> 600
2 -> 10 -> 8 -> 6 -> 17
2 -> 10 -> 8 -> 7 -> 600
2 -> 10 -> 8 -> 7 -> 17
2 -> 100 -> 6 -> 6 -> 600
2 -> 100 -> 6 -> 6 -> 17
2 -> 100 -> 6 -> 7 -> 600
2 -> 100 -> 6 -> 7 -> 17
2 -> 100 -> 7 -> 6 -> 600
2 -> 100 -> 7 -> 6 -> 17
2 -> 100 -> 7 -> 7 -> 600
2 -> 100 -> 7 -> 7 -> 17
2 -> 100 -> 8 -> 6 -> 600
2 -> 100 -> 8 -> 6 -> 17
2 -> 100 -> 8 -> 7 -> 600
2 -> 100 -> 8 -> 7 -> 17
Here is the solution in recursive way:
#include <iostream>
#include <vector>
using namespace std;
void solve(vector < vector<int> >map, vector<int>ans, int pos) {
if(pos == map.size()) {
for(int i = 0; i < ans.size(); i++) {
cout<<ans[i];
if(i != ans.size() - 1) {
cout<<"->";
}
else {
cout<<endl;
}
}
return;
}
for(int i = 0; i < map[pos].size(); i++) {
ans.push_back(map[pos][i]);
solve(map, ans, pos+1);
ans.pop_back();
}
}
int main() {
vector<vector<int> > map = {
{ 1, 2 },
{ 3, 4, 5 },
{ 6, 7 }
};
vector<int>empty;
solve(map, empty, 0);
}
Output:
1->3->6
1->3->7
1->4->6
1->4->7
1->5->6
1->5->7
2->3->6
2->3->7
2->4->6
2->4->7
2->5->6
2->5->7

Getting values from multiple lists to one in Red language

I want to get values from 2 series into one but it is not working:
I have 2 series:
a: [1 2 3]
b: [4 5 6 7]
I want to get all values in one list, so that I can access them as allv/1, allv/2... allv/7.
Following is not working since it makes a series of series and not series of values:
allv: [a b]
print allv ; => prints all 6 values, but following do not work:
print allv/1 ; => gives a (desired is 1)
print allv/2 ; => gives b (desired is 2)
print allv/3 ; => gives none (desired is 3)
I tried following function to combine values in one series:
mycombine: function [ll][
temp: []
foreach l ll [
repeat i length? l [
temp: append temp l/:i ] ]
temp]
mycombine [a b]
But above gives error:
*** Script Error: length? does not allow word! for its series argument
*** Where: length?
*** Stack: rncombine
The series has got converted into word and is not working.
How can I solve this?
Just append
a: [1 2 3]
b: [4 5 6 7]
c: [8 9 10]
d: [11 12 13 14]
>> allv: append a b
== [1 2 3 4 5 6 7]
>> a
== [1 2 3 4 5 6 7]
does what you want. But beware even a contains all values, as you have appendend the values of b to the block a. If you want a new block you have to use
allv: append copy a b
If you want to append more series you can do
>> foreach x [a b c d] [ append [] reduce x]
== [1 2 3 4 5 6 7 8 9 10 11 12 13 14]
Instead of reduce also get x is working.
Another way of combining
>> compose [(a) (b) (c)]
== [1 2 3 4 5 6 7 8 9 10 ]

Haskell Recursive 'sum' Function

I find it really difficult to understand the mechanics of the following recursive function:
sums (x:y:ys) = x:sums(x + y : ys)
sums xs = xs
sums ([0..4])
Output:
[0, 1, 3, 6, 10]
What exactly happens in this line?:
x:sums(x + y : ys)
I would say that before the program can append the 'x' to the list, the function sum(x + y : ys) has to be executed first. But in that case, 'x' would be appended to the list only once - at the end of the recursion loop - which wouldn't result in the given output... so where are the flaws in my logic?
My follow-up question: how should I look at/treat recursive functions in a logical way, that will (hopefully) lead me to an 'aha-erlebnis'?
Any help is much appreciated!
You can understand Haskell code by stepwise reduction. Maybe the following example reduction sequence helps with your aha.
(A Haskell implementation actually does something related to such reduction steps, but maybe in a different order. You get the same end result, though).
In this example, you start with:
sums [0..4]
Expand the [0..4] notation a bit:
sums (0 : 1 : [2..4])
Now we see that the first equation of sums matches, with x = 0, y = 1, and ys = [2..4]. So we get:
0 : sums (0 + 1 : [2..4])
We can compute 0 + 1:
0 : sums (1 : [2..4])
And expand [2..4] a bit:
0 : sums (1 : 2 : [3..4])
Now we see that the first equation of sums matches again, this time with x = 1, y = 2, and ys = [3..4]. So we get:
0 : 1 : sums (1 + 2 : [3..4])
We can compute 1 + 2:
0 : 1 : sums (3 : [3..4])
And expand [3..4] a bit:
0 : 1 : sums (3 : 3 : [4..4])
Now we see that the first equation of sums matches again, this time with x = 3, y = 3, and ys = [4..4]. So we get:
0 : 1 : 3 : sums (3 + 3 : [4..4])
We can compute 3 + 3:
0 : 1 : 3 : sums (6 : [4..4])
And expand [4..4]:
0 : 1 : 3 : sums (6 : 4 : [])
Now we see that the first equation of sums matches again, this time with x = 6, y = 4, and ys = []. So we get:
0 : 1 : 3 : 6 : sums (6 + 4 : [])
We can compute 6 + 4:
0 : 1 : 3 : 6 : sums (10 : [])
This time, the first equation for sums doesn't match. But the second equation matches. So we get:
0 : 1 : 3 : 6 : 10 : []
This is the observed output [0, 1, 3, 6, 10].
This is no different than recursion in any other langauge. When sums [0..4] (the parentheses are unnecessary) is first called, x==0, y==1, and ys == [2..4]. Thus, the return value is a new list created from 0 and sums [1..4].
In a strict language, the recursive call would complete before finally creating the new list. Since Haskell is lazy, a list starting with 0 and continuing with a promise to evaluate sums [1..4] is returned. The recursive call won't actually be evaluated until someone actually tries to access the tail of the list.
You could notice that
sums (x:y:ys) = x:sums(x + y : ys)
is equivalent to
sums (x:y:z:ys) = x:x+y:sums(x+y+z : ys)
sums (x:y:ys) = x:sums(x + y : ys)
and (with more than 2 items) is also equivalent to
sums (x:y:z: w: ys) = x:x+y:x+y+z:sums(x+y+z +w: ys)
sums (x:y:z:ys) = x:x+y:sums(x+y+z : ys)
sums (x:y:ys) = x:sums(x + y : ys)
so by induction you have that
sums(1:2:3:4 :[])
is equal to
1 : 1 + 2 : 1 + 2 + 3 : 1 + 2 + 3 + 4 : []
Based on the above you can also predict that with
fact(x:y:ys) = x: fact(x * y : ys)
fact(xs) = xs
then
fact([1..4])
is
1:1*2:1*2*3:1*2*3*4:[]
There are two equation that define the function sums. Keep rewriting an expression that involves sums using the first equation that matches the argument, or other suitable equations (like 1+2=3).
sums [0..4] =
-- by syntactic sugar
sums (0:1:2:3:4:[]) =
-- by eq. 1, x=0,y=1,ys=2:3:4:[]
0 : sums ((0+1) : 2 : 3:4:[]) =
-- by addition
0 : sums (1 : 2 : 3:4:[]) =
-- by eq. 1, x=1, y=2, ys=3:4:[]
0 : 1 : sums ((1+2) : 3 : 4:[]) =
-- by addition
0 : 1 : sums (3 : 3 : 4:[]) =
-- by eq. 1, x=3, y=3, ys=4:[]
0 : 1 : 3 : sums ((3+3) : 4 : []) =
-- by addition
0 : 1 : 3 : sums (6 : 4 : []) =
-- by eq. 1, x=6, y=4, ys=[]
0 : 1 : 3 : 6 : sums ((6+4):[]) =
-- by addition
0 : 1 : 3 : 6 : sums (10:[]) =
-- by eq 2,xs=(10:[])
0 : 1 : 3 : 6 : 10 : [] =
-- by syntactic sugar
[0,1,3,6,10]

Haskell sort values from list

I'm new to haskell and I want to sort list of strings. For example I have a list that is in my variable ff that contain three strings ["1 8 8 5 6", "1 4 2 3", "5 4 9 7 9 9"] and I want to sort them so my result should look like ["1 5 6 8 8", "1 2 3 4", "4 5 7 9 9 9"] Here's my code that perfectly works
import System.IO
import Control.Monad
import Data.List
import Data.Function
import Data.Array
import Data.Char
sortNumeric = sortBy (compare `on` (read :: String -> Int))
wordsWhen :: (Char -> Bool) -> String -> [String]
wordsWhen p s = case dropWhile p s of
"" -> []
s' -> w : wordsWhen p s''
where (w, s'') = break p s'
main = do
file <- readFile "test.txt"
let ff = map ((!!) (lines file)) [1,3..(length (lines file) - 1)]
let splitString = wordsWhen (==' ') (ff!!0)
let sortedResult = sortNumeric (splitString)
print sortedResult
Problem is with this line let splitString = wordsWhen (==' ') (ff!!0) I always get first element of the list, so only first element is sorted. How can I pass all values of a list? Here's what I tryied to do let splitString = wordsWhen (==' ') (ff!![0..(length(ff)-1)]) unfortunately this doesn't work. Any ideas how to solve this problem?
You can do it easily with map and a niftry trick to use words, sort and then unwords (to restore the whitespace).
Prelude> let ff=["1 8 8 5 6", "1 4 2 3", "5 4 9 7 9 9"]
Prelude> import Data.List
Prelude Data.List> map (unwords . sort . words) ff
["1 5 6 8 8","1 2 3 4","4 5 7 9 9 9"]
Edit: Improvement to correctly sort numeric values:
import Data.List
let ff=["11 8 8 5 6", "11 4 2 3", "5 4 9 7 99 9"]
let sortNumeric = (map show) . sort . (map (read :: String -> Int))
map (unwords . sortNumeric . words) ff
result:
["5 6 8 8 11","2 3 4 11","4 5 7 9 9 99"]

What is going on in this function (haskell)?

I have this haskell function that I don't quite understand.
ns :: [Integer]
ns = 0 : [n+k | (n, k) <- zip ns [1,3..]]
I am asked to "take 3 ns".
I thought ns was constant so it would only zip with the first element of the list, giving (0,1). Then when added gives an answer of 1. Then it says "take 3 ns" so I zipped 0 with the first 5 elements of the list, giving... (0,1),(0,3), (0,5) and then when added, I get a final answer of [1,3,5]. However this isn't the correct answer.
What is actually happening to ns? I'm struggling to understand...
haskell is lazy so you can have recursive definitions. Here it is laid out.
ns = 0 : something
(n,k) <- zip (0 : something ) [1,3,5,7...]
(n,k) <- [(0,1) : something )
ns = 0 : 1 : something
(n,k) <- zip ( 0 : 1 : something ) [3,5,7...]
(n,k) <- (0,1) : (1,3) : something
ns = 0 : 1 : 4 : something
(n,k) <- zip ( 0 : 1 : 4 : something ) [5,7...]
(n,k) <- (0,1) : (1,3) : (4,5) : something
ns = 0 : 1 : 4 : 9 : something
....
See how we determine what the next tuple is then add its two elements. This allows us to determine the next element.
Everything in Haskell is lazy, so while ns is constant, that doesn't mean items in the list can't be "added" (or more accurately, "computed") at a later time. Also, because ns is recursively defined, values that appear later in the list can depend on values that appear earlier in the list.
Let's go over this step by step.
First, we know that ns starts with 0, so for the time being, ns looks like this:
ns: 0, ?, ?, ...
So what's in the first question mark? According to your function, it's n + k, where n is the first element in ns, and k is the first element in [1, 3..]. So n = 0, k = 1, and n + k = 1.
ns: 0, 1, ?, ...
Moving on, the next element is also n + k, where we use the second elements of ns and [1, 3...]. We now know that the second element of ns is 1, so n = 1, k = 3, and n + k = 4.
ns: 0, 1, 4, ...
And so on.
Haskell evaluates things lazily, so it'll only compute exactly as much of a value is needed. That means we need to somehow need values of ns to see how it's computed.
head ns
head (0 : ...)
0
Clearly, head doesn't force enough for anything interesting to happen, but you can already see that the interesting part of ns is just discarded. That effect goes further when we ask for more, such as printing each element. Let's just force each element one after another to see the pattern. First, let's replace the list comprehension with a single equivalent function call
zipWith f [] _ = []
zipWith f _ [] = []
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
ns = 0 : zipwith (+) ns [1,3..]
Now we can evaluate elements of ns one by one. Really, to be more detailed, we're evaluating ns and determining that the first constructor is (:) and then deciding to evaluate the second argument to (:) as our next step. I'll use {...} to represent a not-yet-evaluated thunk.
ns
{ 0 } : zipWith (+) ns [1,3...]
{ 0 } : zipWith (+) ({ 0 } : { ... }) [1,3...] -- notice the { 0 } thunk gets evaluated
0 : { 0 + 1 } : zipWith f { ... } [3,5...]
0 : 1 : { 1 + 3 } : zipWith f { ... } [5,7...]
0 : 1 : 4 : { 4 + 5 } : zipWith f { ... } [7,9...]
What's important to note above is that since ns get evaluated only piece by piece, it never demands to know something that has not yet been computed. In this way, ns forms a tight, clever little loop all in itself.
That's equivalent to ns = 0 : (zipWith (+) ns [1,3,...]) , which may be easier to comprehend: the k+1th element is the kth element plus k-th odd number, with appropriate starting conditions.
ns :: [Integer]
ns = 0 : [n+k | (n, k) <- zip ns [1,3..]]
this is a corecursive data definition. ns is a constant, a list, but it is "fleshed out" by access, since Haskell is lazy.
An illustration:
1 n1 n2 n3 n4 n5 ... -- the list ns, [n1,n2,n3,...],
2 0 1 4 ... -- starts with 0
3 -----------------
4 1 3 5 7 9 -- [1,3..]
5 -----------------
6 1 4 ... -- sum the lines 2 and 4 pairwise, from left to right, and
7 n2 n3 n4 n5 ... -- store the results starting at (tail ns), i.e. from n2
We can see precisely how access is forcing the list ns into existence step by step, e.g. after print $ take 4 ns, by naming the interim entities:
ns :: [Integer]
ns = 0 : [n+k | (n, k) <- zip ns [1,3..]]
ns = 0 : tail1
tail1 = [n+k | (n, k) <- zip ns [1,3..]]
= [n+k | (n, k) <- zip (0 : tail1) [1,3..]]
= [n+k | (n, k) <- (0,1) : zip tail1 [3,5..]]
= 1 : [n+k | (n, k) <- zip tail1 [3,5..]]
= 1 : tail2
tail2 = [n+k | (n, k) <- zip (1 : tail2) [3,5..]]
= [n+k | (n, k) <- (1,3) : zip tail2 [5,7..]]
= 4 : tail3
tail3 = [n+k | (n, k) <- zip (4 : tail3) [5,7..]]
= 9 : tail4
tail4 = [n+k | (n, k) <- zip (9 : tail4) [7,9..]]
------
ns = 0 : 1 : 4 : 9 : tail4