I suppose anything is cryptic if you make no effort to understand it.
Even so, your statement is very odd. Apparently you are under the mis-apprehension that your failure to understand is the fault of a succinct, powerful notation and this means that the language was "deliberately" designed to be hard to understand.
Why would you even think something like this? I mean, why would someone deliberately make something difficult to understand? Most people I know strive for clarity. Do you think that "1+1" is cryptic because it uses a symbol "+" instead of the word "plus"? I suppose it is if you don't know math.
The other odd thing you seem to imply is that avoiding hard, unnecessary work is a bad thing. So, you're against the idea of carefully designed, well-tested, powerful, pre-written functions that you can combine in a clear, logically consistent manner?
This is all the more puzzling as your initial answer
join (table comb) [0..]
apparently very closely resembles the J solution of
i. !/ i.
because each "i." generates a vector of consecutive integers and "/" - similarly to (table comb) - combines these vectors in a table using "!". The "!" function, with a right and left arguments x and y returns the number of ways x things can be chosen from y possibilities - pretty much a direct statement of what you are doing when determining the coefficient of a polynomial expansion.
There are, of course other ways to do this more algorithmically and less mathematically as you appear to show in your final example. I say "appear" because that example is rather cryptic insofar as it uses the pre-written function "zipWith".
In J, I could write something I presume is similar to this:
pascalNewRow=: 3 : '1,(2+/\y),1'
based on the following rule for generating a new row of the triangle from the previous one: start and end with 1; add together adjacent pairs for the middle section. The above expression "2+/\" adds together each adjacent 2 numbers across the first dimension of an array; the "3 :" defines a function. Once you know that, the code is a straightforward expression of the rule.
Similarly to the final expression in Haskell, we iterate the function "pascalNewRow" by using an iterator expressed by some symbols, "^:" instead of the word "iterate". So, the expression
pascalNewRow^:10 ] 1
returns the first ten rows of Pascal's triangle (starting with a "seed" of 1).
I find this much less cryptic than the Haskell expression but, of course, I've made the effort to understand it.
In any case, this has wandered far off topic. Why don't I conclude by giving a solution to the original problem? Taking my J code as a template, start by defining a function to add adjacent pairs of a vector:
int *addAdjacentPairs( int vlen, int *vec)
{ int vc, win2[2];
win2[0]=0;
win2[1]=vec[0];
for(vc=0;vc<=vlen;vc++)
{ vec[vc]=win2[0]+win2[1];
win2[0]=win2[1];
win2[1]=vec[vc+1];
}
// Danger: returned vector is 1 longer than input: allocate accordingly.
return 0;
}
and simply use it in a loop:
// PascalTriangle.c: print some rows of Pascal's triangle.
#include<stdio.h>
int main(void)
{ int vec[21];
int ii,vc,nn;
printf("How many lines (up to 20) do you want? ");
scanf("%d",&nn);
// Should verify result and handle errors but this is why I don't like these
// languages that don't handle arrays natively so I won't bother.
printf("\n");
for(ii=0;ii<nn;ii++)
{ vec[ii]=1;
for(vc=0;vc<=ii;vc++) printf("%i ",vec[vc]);
printf("\n");
addAdjacentPairs( ii, vec);
}
return 0;
}
This provides a nice example of how solving the problem with a high-level notation leads to a more elegant solution even in a lower-level language.
Originally Posted by
sarehu
That's because J is deliberately cryptic and hides all the hard work behind pre-written combinators and functions, in this case ! being "choose". Given the equivalent of these two defined in Haskell:
comb n k = foldl' (\x y -> ((n - x + 1) * y) `div` x) 1 [1..k]
table f xs ys = foldr ((:) . (`map` ys) . f) [] xs
Then producing Pascal's triangle is as simple as join (table comb) [0..] .
But overall a much simpler solution is
iterate (\xs -> zipWith (+) (0:xs) (xs++[0])) [1]