Thanks Martin_H for jumping in on the LISP - Forth discussion.
EDIT: didn't see your last post above ...
in Tachyon (the only Forth I know a little)
there is
ACALL ( adr -- ) Call arbitrary (from the stack) address - used to execute user vectors
EDIT: so this is like the execute word, but works on vectors, not direct adresses (the way Tachyon handles this)
need to check how Peter handles the new CALL16 instructions.
The ' word gives the address of the following word (actually the vector for it) and puts it on the stack so it can be stored somewhere and called by ACALL later.
Peter has an example somewhere using a 'vector of function pointers' - when I find it I add it here.
Of course this is not yet an anonymous function / lambda, but a good start.
And Tachyon provides a lot of introspection capabilities.
Martin is right, a lambda is not just the equivalent to a function pointer in C.
A lambda "remembers" the variables that were in scope at the time it was created.
In C++ they have recently (2011?) introduced lambdas. Basically there, a lambda creates a whole new object with the lambda function as a method and the available in scope variables as properties. Crude but effective.
Also as Martin says, Java did not get lambdas until recently. But then neither did C# in version 3.0 circa 2007.
As we see, JavaScript, which had lambdas since it's beginning in 1995 and much cleaner syntax for them, is such a superior language that all the others try very hard to become like it
Quite frankly I don't know why they bother. Once you have C++ you can create JavaScript and then you are done.
Martin is also right about the "tangled slinky" code made possible by lambdas. In the old days, when we had GOTO, people complained about the resulting "spaghetti" code that GOTO made possible. Lambdas and the resulting "tangled slinky" code is even worse. Don't do that.
Small print: There may or may not be sarcasm in some or all of this post. You will find a grain of truth if you look had enough.
Martin is also right about the "tangled slinky" code made possible by lambdas. In the old days, when we had GOTO, people complained about the resulting "spaghetti" code that GOTO made possible. Lambdas and the resulting "tangled slinky" code is even worse. Don't do that.
I don't think this is quite fair. Yes, you can write messy code with lambda but you can also use it to good effect and in the process create higher order functions that are very flexible. In fact, C programs have used what are essentially lambda expressions for a long time. How often have you seen a C function that takes a pointer to a function (usually a callback) and a void* pointer to be passed to the function. The combination of that function pointer and void* pointer is essentially a lambda. Of course, now everyone will complain that callbacks are bad. :-)
How often have you seen a C function that takes a pointer to a function (usually a callback) and a void* pointer to be passed to the function.
Yes indeed. You mean like when creating a thread using the pthreads API for example? A pointer to the function to run as a thread and a pointer to some data to pass as an argument to that function.
Similarly one can also do object oriented programming in C by passing a pointer to "object" data in all calls of the objects "methods". And so on.
We could say that all higher level languages are redundant because it can all be done in C.
We could say that C is redundant because whatever it does can be done in assembler. Well, actually no thinking about it because C is portable and assembler is not.
What about other HLLs? Can we do everything that lisp does in C as well? Or, dare I say it, Forth?
Yes indeed. You mean like when creating a thread using the pthreads API for example? A pointer to the function to run as a thread and a pointer to some data to pass as an argument to that function.
Similarly one can also do object oriented programming in C by passing a pointer to "object" data in all calls of the objects "methods". And so on.
We could say that all higher level languages are redundant because it can all be done in C.
We could say that C is redundant because whatever it does can be done in assembler. Well, actually no thinking about it because C is portable and assembler is not.
What about other HLLs? Can we do everything that lisp does in C as well? Or, dare I say it, Forth?
I wasn't trying to argue that using a function pointer and a void* was better or worse than using a closure (should have called it that instead of lambda) in Lisp. I was just pointing out that a similar programming technique is used in many different languages. It isn't unique to Lisp or Javascript or any other language.
Most Forths contain a source level interpreter that can be applied to console I/O, files or strings. Few C compilers have this capability. I'm only familiar with PicoC that can do this, but there may be others. Basic interpreters can usually interpret files as well as console input. Some may be able to interpret source code in strings. I don't know whether Lisp or any of the HLLs have this capability.
There are some Forths that do not contain a source level interpreter, and can only execute cross-compiled code.
Most Forths contain a source level interpreter that can be applied to console I/O, files or strings. Few C compilers have this capability. I'm only familiar with PicoC that can do this, but there may be others. Basic interpreters can usually interpret files as well as console input. Some may be able to interpret source code in strings. I don't know whether Lisp or any of the HLLs have this capability.
There are some Forths that do not contain a source level interpreter, and can only execute cross-compiled code.
Pretty much any Lisp system will support the EVAL function that takes an S-expression and interprets it as Lisp code.
I believe you are right, many (all?) programming techniques can be done in many (all?) programming languages.
It seems to me that this does not happen in general practice because people don't generally know about the idea or it's just to damn hard, verbose and confusing to do in whatever language they are using.
For example many iterative loops can be programmed more cleanly as a recursive functions. A C programmer would never dream to do that, "It's going to blow up my stack, all that function calling is much slower" he'd say. But in a language with tail call optimization it might be the most natural thing in the world to do. And as fast as that C code.
A C programmer could get by for years without ever thinking about recursion, call backs, lambdas, closures, functional programming and so on.
Heck I got by for a long while in C with never using dynamic memory allocation. I've used an HLL that does not have any kind of loop construct at all!
Programming languages tend to emphasis certain techniques or styles over others. It's good to be exposed to many of them.
But, I swear, JS can do things you could never craft in assembler
It might be not so much the language itself,
but the combination of language, interactive environment
and introspectable data structures, that are not hidden in a compiler level,
that give LISP and to a lesser degree FORTH a special expressiveness.
The 'programs are lists' approach in LISP opens up huge potential to programatically
manipulate programs.
Try to do this in C ... - sure it is possible ;-)
Anyhow - I only wanted to encourage David to have a look at Tachyon and give it a chance.
It is much better suited to a MCU than a LISP - I ran it on a Symbolics LISP machine - a very different animal than a PROPELLER ;-)
I am happy I did get over the initial - 'I'll never get used to this reverse thing' when I started with Tachyon-Forth.
Most Forths contain a source level interpreter that can be applied to console I/O, files or strings. Few C compilers have this capability.
To true.
It has often bugged be that it's not easy (or even possible) for a C program to run a string containing C code. One could shell out to a C compiler, compile the string and run it. But that's not the same as eval in languages like lisp or JS where the evaluated and run string has access to the variables in the program that evaled it.
But recently I discovered this amazing thing. It's an interpreter for C++. It comes from CERN it's called "cling". Mind bending.
I start to wonder if C++ can have the equivalent of eval with cling.
Many in the JS world say that eval is evil. But as we know evil has a beauty all it's own and eval enables some amazing things.
Yes the access to the interpreter makes many things exeptionally easy.
Like how Peter implements the FTP-server in TACHYON.
He just defines the FTP commands as Forth words and redirects the NW-stream to the
Forth interpreter loop and lets it handle all the parsing.
VERY effective.
This is part of the 'miracle' how he manages to get such a functionality in such little code space.
FTP, TELNET, HTTP, EMAIL, SD, ....
And thats the base that allowed me to implement a dynamic (TACHYON Forth) scriptable webserver with JSON
in very few lines/bytes of code.
e.g. in the JSON writer I want to write a Forth variable as a named entity,
kind of key - value pair.
Forth
var JB
can print "var: valueOfVar" because Forth can introspect and get the name of the variable, so I do not need to duplicate it, as I would do normally (Basic like)
For me the selling point for FORTH is that you extend the language into a domain specific language for the problem at hand. In turn this allows a human readable serial protocol for whatever widget you're controlling right out of the box. It's a seriously cool language and one I'm glad I put in the effort to learn.
But it comes at the cost of a syntax which is off putting to many people, and the serial control protocol which has unlimited control of the system. This can be a bad thing if the controller has a bug and issues commands which screw up the system. That won't happen with a C program because the protocol is only data, not code.
I did my junior project in Inter-Lisp on an Atari 800 xl. This machine had 64KB of RAM of which about 8 KB was consumed by video RAM and I/O buffers. This is only slightly more than the Propeller, and given its expressive power, Lisp is far more friendly to a low resource machine than most people expect. I was able to build a game tree engine and simple AI for playing games. It wasn't a speed demon, but it worked.
Good on ya, Peter. I think chatting about countries is fine & dandy here.
You Aussies are very fun-loving have a great thing going down under, other than making margaritas with an egg. In a nice Sydney bar, Rocks area, October 1985, a bartender made me a yellow margarita. The only drink I have ever sent back. Fortunately he was a very friendly fellow and I got him sorted out with my favorite recipe. 1/8 lime juice, 1/8 triple sec, 1/4 tequila and 1/2 sweet & sour mix. Zero eggs.
Uh-oh. Alcohol talk. I may have just crossed the line...
I have to say mate, that bloke played a "yoke" on you for sure But what do you expect coming to Oz and ordering a margarita, for yourself! That's not a drink! That's a shiela's drink. Mind you, it is the Rocks, so it might be on the cards.
On the highways there is a solid center line with a dashed line on the other side of it, so it's ok to cross from the dashed side, but you can't cross from the other side, although I believe hot wheels just run down the center. So my Aussie version of an Irish blessing is "May the dashes always be on your dry side, so that you may be able to cross over to the wet side. May your beer be cold, and your company warm". Still no margaritas in that blessing though.
I almost spilled my drink reading this thread title.
You forgot to start with your name: "My name is Peter, I am Australian and I use Forth".
I am still fascinated by Tachyon, but also still can't wrap myself around Forth.
Never got the hang on HP calculators either. Sure - I do grasp the concept. And I can see the simplicity and beauty(?) in it. But somehow my mind is rejecting it. Sad.
I found reading up on eForth really was helpful. The goal was the smallest amount of code to build a Forth stack machine.
Tachyon has some sophisticated enhancements. So it takes a bit more effort to appreciate its Forth stack machine. Starting with Dave Hein's pfth really allowed me to understand what Forth does, and I could see how it was doing it in PASM by reading up on eForth.
But be forewarned that some of the documentation wanders deeply into trying to link Zen to Forth. I guess you just have to appreciate how wacky programmers were way back then. Mastering Forth might also make one a Zen master as well.... eh, Grasshopper?
Comments
Yes.
Yes, that's exactly what it does. I haven't used Tachyon, but execution tokens have been in all the FORTH's I've used.
EDIT: didn't see your last post above ...
in Tachyon (the only Forth I know a little)
there is
ACALL ( adr -- ) Call arbitrary (from the stack) address - used to execute user vectors
EDIT: so this is like the execute word, but works on vectors, not direct adresses (the way Tachyon handles this)
need to check how Peter handles the new CALL16 instructions.
The ' word gives the address of the following word (actually the vector for it) and puts it on the stack so it can be stored somewhere and called by ACALL later.
Peter has an example somewhere using a 'vector of function pointers' - when I find it I add it here.
Of course this is not yet an anonymous function / lambda, but a good start.
And Tachyon provides a lot of introspection capabilities.
A lambda "remembers" the variables that were in scope at the time it was created.
In C++ they have recently (2011?) introduced lambdas. Basically there, a lambda creates a whole new object with the lambda function as a method and the available in scope variables as properties. Crude but effective.
Also as Martin says, Java did not get lambdas until recently. But then neither did C# in version 3.0 circa 2007.
As we see, JavaScript, which had lambdas since it's beginning in 1995 and much cleaner syntax for them, is such a superior language that all the others try very hard to become like it
Quite frankly I don't know why they bother. Once you have C++ you can create JavaScript and then you are done.
Martin is also right about the "tangled slinky" code made possible by lambdas. In the old days, when we had GOTO, people complained about the resulting "spaghetti" code that GOTO made possible. Lambdas and the resulting "tangled slinky" code is even worse. Don't do that.
Small print: There may or may not be sarcasm in some or all of this post. You will find a grain of truth if you look had enough.
Similarly one can also do object oriented programming in C by passing a pointer to "object" data in all calls of the objects "methods". And so on.
We could say that all higher level languages are redundant because it can all be done in C.
We could say that C is redundant because whatever it does can be done in assembler. Well, actually no thinking about it because C is portable and assembler is not.
What about other HLLs? Can we do everything that lisp does in C as well? Or, dare I say it, Forth?
There are some Forths that do not contain a source level interpreter, and can only execute cross-compiled code.
I believe you are right, many (all?) programming techniques can be done in many (all?) programming languages.
It seems to me that this does not happen in general practice because people don't generally know about the idea or it's just to damn hard, verbose and confusing to do in whatever language they are using.
For example many iterative loops can be programmed more cleanly as a recursive functions. A C programmer would never dream to do that, "It's going to blow up my stack, all that function calling is much slower" he'd say. But in a language with tail call optimization it might be the most natural thing in the world to do. And as fast as that C code.
A C programmer could get by for years without ever thinking about recursion, call backs, lambdas, closures, functional programming and so on.
Heck I got by for a long while in C with never using dynamic memory allocation. I've used an HLL that does not have any kind of loop construct at all!
Programming languages tend to emphasis certain techniques or styles over others. It's good to be exposed to many of them.
But, I swear, JS can do things you could never craft in assembler
but the combination of language, interactive environment
and introspectable data structures, that are not hidden in a compiler level,
that give LISP and to a lesser degree FORTH a special expressiveness.
The 'programs are lists' approach in LISP opens up huge potential to programatically
manipulate programs.
Try to do this in C ... - sure it is possible ;-)
Anyhow - I only wanted to encourage David to have a look at Tachyon and give it a chance.
It is much better suited to a MCU than a LISP - I ran it on a Symbolics LISP machine - a very different animal than a PROPELLER ;-)
I am happy I did get over the initial - 'I'll never get used to this reverse thing' when I started with Tachyon-Forth.
It has often bugged be that it's not easy (or even possible) for a C program to run a string containing C code. One could shell out to a C compiler, compile the string and run it. But that's not the same as eval in languages like lisp or JS where the evaluated and run string has access to the variables in the program that evaled it.
But recently I discovered this amazing thing. It's an interpreter for C++. It comes from CERN it's called "cling". Mind bending.
I start to wonder if C++ can have the equivalent of eval with cling.
Many in the JS world say that eval is evil. But as we know evil has a beauty all it's own and eval enables some amazing things.
Like how Peter implements the FTP-server in TACHYON.
He just defines the FTP commands as Forth words and redirects the NW-stream to the
Forth interpreter loop and lets it handle all the parsing.
VERY effective.
This is part of the 'miracle' how he manages to get such a functionality in such little code space.
FTP, TELNET, HTTP, EMAIL, SD, ....
And thats the base that allowed me to implement a dynamic (TACHYON Forth) scriptable webserver with JSON
in very few lines/bytes of code.
e.g. in the JSON writer I want to write a Forth variable as a named entity,
kind of key - value pair.
Forth can print "var: valueOfVar" because Forth can introspect and get the name of the variable, so I do not need to duplicate it, as I would do normally (Basic like)
But it comes at the cost of a syntax which is off putting to many people, and the serial control protocol which has unlimited control of the system. This can be a bad thing if the controller has a bug and issues commands which screw up the system. That won't happen with a C program because the protocol is only data, not code.
I did my junior project in Inter-Lisp on an Atari 800 xl. This machine had 64KB of RAM of which about 8 KB was consumed by video RAM and I/O buffers. This is only slightly more than the Propeller, and given its expressive power, Lisp is far more friendly to a low resource machine than most people expect. I was able to build a game tree engine and simple AI for playing games. It wasn't a speed demon, but it worked.
I have to say mate, that bloke played a "yoke" on you for sure But what do you expect coming to Oz and ordering a margarita, for yourself! That's not a drink! That's a shiela's drink. Mind you, it is the Rocks, so it might be on the cards.
On the highways there is a solid center line with a dashed line on the other side of it, so it's ok to cross from the dashed side, but you can't cross from the other side, although I believe hot wheels just run down the center. So my Aussie version of an Irish blessing is "May the dashes always be on your dry side, so that you may be able to cross over to the wet side. May your beer be cold, and your company warm". Still no margaritas in that blessing though.
You forgot to start with your name: "My name is Peter, I am Australian and I use Forth".
I am still fascinated by Tachyon, but also still can't wrap myself around Forth.
Never got the hang on HP calculators either. Sure - I do grasp the concept. And I can see the simplicity and beauty(?) in it. But somehow my mind is rejecting it. Sad.
Anyways.
My name is Mike, I am German and I used COBOL....
Enjoy!
Mike
Tachyon has some sophisticated enhancements. So it takes a bit more effort to appreciate its Forth stack machine. Starting with Dave Hein's pfth really allowed me to understand what Forth does, and I could see how it was doing it in PASM by reading up on eForth.
http://www.offete.com/files/zeneForth.htm
But be forewarned that some of the documentation wanders deeply into trying to link Zen to Forth. I guess you just have to appreciate how wacky programmers were way back then. Mastering Forth might also make one a Zen master as well.... eh, Grasshopper?
http://www.ultratechnology.com/efzen.htm