Perlis Languages
blog.fogus.me
blog.fogus.me
void shuffle(int *array, int n) {
int i, j, tmp;
for (i = n - 1; i > 0; i--) {
j = rand_int(i + 1);
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
}
}
With the same algorithm in Forth: : shuffle
1- for
i 1+ random over +
over i +
swap@
next
;
The types, intermediate variables and many of the unnecessary details of the implementation fall away. It's an aesthetic distinction, since we're really trading these for "stack noise" words like over and i, but I find it very pleasing.C is normally considered an extremely simple, lightweight language. I think the main lesson Forth has taught me is that we can design much simpler languages in the same space without sacrificing power and flexibility.
But perhaps at the expense of readability. Forth-like languages look quite elegant in small examples but C's more explicit syntax scales much better to larger code bases, IMO.
: shuffle
This starts a declaration for our word 'shuffle'. This implementation expects the address of the array on the stack with the length of the array on top. Some Forth programmers would leave a comment to this effect like so: ( addr len -- addr )
Anything in parentheses is a comment, and this shows the contents of the stack we want as input (read from right to left) before the '--' followed by the contents of the stack we'll get as output. (We leave the array address on the stack. If we want to be void like the C example, add a drop to the end of this definition to discard it.) 1- for
Subtract one from the length given and begin a for...next loop. This will take the length value off the stack and repeat everything up to the matching next n+1 times. Equivalent to: for(int z=n; z >= 0; z--) {}
Our stack now looks like this: ( addr )
While we're in the loop, a copy of the loop index can be pushed onto the stack via the word i. This actually accesses a secondary stack, so if you nest loops you can obtain progressive indices by using i' and j (or j and k, depending on your Forth dialect.) i 1+ random
Add one to the loop index and generate a random number between 0 and this value, exclusive. Our stack now looks like: ( addr rand_int(i+1) )
over +
Over pushes a copy of the second element of our stack. This sequence adds the address of the array to the random index, leaving the address of that cell of the array. Our stack now looks like this: ( addr (rand_int(i+1)+addr) )
over i +
Make another copy of the array address and add the loop index to it. The stack now looks like this: ( addr (rand_int(i+1)+addr) (i+addr) )
swap@
This is a helper word which swaps the contents of two memory addresses. It should be easy to see that this will swap array indices for us in exactly the same way the C code did. next ;
Close the loop and terminate the word definition, respectively.[Thanks a lot by the way!]
It takes some time to get used to dealing with the stack. The stack plus the fact that there aren't many "structural" symbols like the parentheses and curly braces of ALGOL-derived languages can certainly make Forth harder to skim at first. On the other hand, idiomatic Forth code should be factored into many very small definitions. Aggressive decomposition wins back some readability since everything will be in tiny bite-sized chunks, and it promotes reusing code too. I think personal preference is part of it.
If you're serious about learning more, I'd recommend Leo Brodie's Starting Forth: http://www.forth.com/starting-forth/sf1/sf1.html
I hate plugging my own projects, but if you check out my profile I also have several Forth-related things on github.
I'm rather happy that many of these are "modern" languages: Qi, Oz, Kernel, and similar raise my hopes for the field showing that in the interceding 50 years, we have improved upon Lisp, ML, Prolog, and the like.
Few concepts are unique to any computer language, so I would argue that it should be about learning new concepts rather that a new programming language.
Some of the examples he picks are rather good at that, since they contain concepts not part of the mainstream paradigms, and so will have new concepts for most programmers.
https://github.com/raganwald/homoiconic/blob/master/2008-11-...
Just be warned that I'm coming at it from the outside with most of these languages, to make your final decision try and find someone experienced in multiple languages from the paradigm and ask them which to learn the paradigm with.
As a fun learning adventure it's interesting - and, as the article says a lot, mind-blowing - but I can read and understand what is going on in C.
Ask me to explain what Forth, or most if not all of the other examples are doing and you'd be lucky to get more than an, "eeeerrrrrrrrrrrrrrrr...." from me. I suppose that experimentation and innovation are more the point with this though.
PHP is based on C. It is not based on Forth. Thus, if you only know PHP, C code will be more immediately clear to you than Forth code.
There are some things that make languages easier or harder to read in absolute terms, but when you're brand new, similarity to what you already know pretty much dominates everything else. Similarly, English speakers tend to find Spanish easier than Russian or Chinese.
Language design is not simply a balance between terseness and verbosity, it's a complex series of tradeoffs between many paradigms and features- some allow you to express ideas more succinctly, flexibly or reliably.