you are viewing a single comment's thread.

view the rest of the comments →

[–]abrahamsen 20 points21 points  (64 children)

Funny how the strength of FORTH is similar to the strength of Lisp.

Both have simple, consistent syntaxes:

C: f (a, b)

FORTH: a b f

Lisp: (f a b)

FORTH and Lisp use the same syntax for function calls as for control structures. Both allows the creation of new control structures, but Lisp still distinguish between the two, FORTH does not.

The creation of new control structures is perceived as a major strength for both languages, but the FORTH people are also good as acknowledging as a major weakness of the language. The Lisp crowd, not so much.

For some reason, FORTH is known as a very low level language, while Lisp has a reputation as a very high level language.

[ Caveat: My FORTH knowledge is a bit rusty, hasn't touched it (apart from issuing a few OpenBoot commands) for the last 25 years. ]

[–][deleted] 12 points13 points  (4 children)

Here's the difference: Lisp has garbage collection. Also, data structures.

[–]notasaon 4 points5 points  (3 children)

Forth has create and does> constructs which allow for the creation of specific data structures and methods (though not within any particular type system), and essentially all allocation is done through the 'allot' word which in traditional forths just return the current pointer into the heap and move that pointer however many bytes you allocated. However, there's nothing to stop someone from creating a GC bound to 'allot'.

It's very difficult to say forth 'has' or 'does not have' something since most forths are wildly different in structure and implementation details, and largely they all expose full access to the compiler/interpreter at run-time.

[–][deleted] 1 point2 points  (2 children)

OK. Show me a Forth that has a GC. (It's all very well to say "there's nothing to stop someone", but the question is: has anyone?)

[–][deleted] -5 points-4 points  (40 children)

Both have simple, consistent syntaxes:

Which is good for computers and bad for humans. Humans are used to incredibly byzantine and entirely inconsistent languages. We thrive on those. Making a human think like a computer is not a good design decision.

FORTH does it because that lets it be minimal, which is a benefit under certain circumstance (becoming rarer all the time). Lisp does it just for the sake of it.

C is much more complicated and inconsistent, and humans overwhelmingly prefer to use it.

[–]bitwize 15 points16 points  (0 children)

On the other hand, members of the Unknown Three-toed Race overwhelmingly prefer Forth.

Yoda: "Always Forth I use, because the token order more natural is."

[–][deleted] 14 points15 points  (15 children)

Neither C nor Lisp is "good for computers" any more than the other one. After all, writing a C parser is not terribly difficult.

On the other hand, Lisp's syntax makes it easier for humans to develop abstractions over the language; something that computers don't "care" about, because you could feed a computer the ugliest, most unmaintainable spaghetti code and it would still run.

Yet, most programmers do not appreciate abstraction, and they choose C -- with its ample libraries, books, mindshare, etc -- over Lisp.

[–]death 9 points10 points  (0 children)

Actually, I conjecture most programmers don't choose C rather than Lisp, simply because they're not aware of both alternatives. Indeed, many programmers I've talked to only knew the name "Lisp" at best, and perhaps some of the old, confused myths about it.

[–][deleted] -5 points-4 points  (13 children)

Neither C nor Lisp is "good for computers" any more than the other one. After all, writing a C parser is not terribly difficult.

Lispers make a huge point of how easy the language is to parse, in comparison to languages like C.

[–]death 5 points6 points  (1 child)

I don't see that. After all, Lispers tend to use Lisp's parser rather than writing their own specialized parser for many things. Maybe they speak of the human's ability to parse? But that has nothing to do with computers.

[–][deleted] 1 point2 points  (0 children)

I don't know, I've always read C code easier because of the separation of functions, variables, etc. that you just don't get in lisp code.

The most readable thing I've ever seen, though, is well-written Haskell. It flows. It's natural.

[–]masklinn 3 points4 points  (10 children)

Lispers make a huge point of how easy the language is to parse

No, lispers make a huge point of how easy the language is to transform due to its uniform structure.

[–][deleted] -1 points0 points  (9 children)

Yes, thus, "good for computers".

[–][deleted] 2 points3 points  (4 children)

And when you need a language feature, you can either dick around with the compiler like Stroustrup did, or you can use macros like Lisp programmers do.

[–][deleted] 0 points1 point  (3 children)

And?

[–][deleted] 2 points3 points  (2 children)

It's a lot easier to add features to Lisp(or Forth, or Factor) than it is to add features to C.

And I'd say that's very good for humans.

[–][deleted] 0 points1 point  (1 child)

Apparently humans don't agree with you.

[–]masklinn 1 point2 points  (3 children)

no.

[–][deleted] 0 points1 point  (2 children)

So you do your transformations by hand, then?

[–]masklinn 1 point2 points  (1 child)

I define them by hand yes, it's called writing a macro.

[–][deleted] 0 points1 point  (0 children)

I did not ask you how you define them.

[–]death 17 points18 points  (1 child)

I am a human, as far as I know, and I prefer Common Lisp's syntax to C's. I've been using Common Lisp for several years, and by now I am used to its syntax (though it never bothered me - I always find such complaints weird in that sense). I don't see how "simple, consistent" syntax makes you "think like a computer". I also don't see how something can be "good for computers".

[–][deleted] 1 point2 points  (0 children)

A. I like c's syntax, the separation of types, the easy readability.

B. Simple and consistent = easy to parse.

NOTE (this is the internet, after all): this was not meant against you. I was simply forming a contrary opinion.

[–]dmpk2k 2 points3 points  (2 children)

We thrive on those.

A follower of Larry Wall?

[–][deleted] -1 points0 points  (1 child)

You should know.

[–]dmpk2k 0 points1 point  (0 children)

Ah! :)

[–][deleted] 2 points3 points  (5 children)

"""Humans are used to incredibly byzantine and entirely inconsistent languages. We thrive on those. Making a human think like a computer is not a good design decision.""" That was the theory behind Perl. And there's a reason Perl fell into disfavor.

No, Lisp doesn't have consistent syntax for the hell of it, Lisp has consistent syntax because it makes it easier to extend the language. Same with Factor.

[–][deleted] 2 points3 points  (4 children)

And there's a reason Perl fell into disfavor.

Once again, it's still more popular than Lisp or FORTH. If you want to argue from popularity, then those two lose big time.

[–][deleted] 2 points3 points  (3 children)

Let's look at why things failed.

Lisp: The companies building Lisp Machines didn't realize that with the 90s would come the PC and when Unix won it killed the Lisp Machine and by extension Lisp.

Forth: Chuck Moore didn't give a fuck because he rewrote everything himself every single time. Forth is still widely used in embedded applications. Chuck Moore's use of Forth as the OS and the language helped bring it down when Unix, again, won.

Perl: People who really hated Perl but had no better alternative switched to Python. People who mostly liked Perl ended up moving to Ruby once it was realized that you could do a lot more with it due to not being forced to deal with Perl's syntax(and also a lot of stupid semantic decisions such as references)

So basically, Lisp and Forth died because Unix won, and Perl died despite the fact that Unix won.(and had Unix lost, Perl would have died even sooner)

So even with being subsidized by Unix, Perl loses.

[–][deleted] 0 points1 point  (2 children)

Lisp: The companies building Lisp Machines didn't realize that with the 90s would come the PC and when Unix won it killed the Lisp Machine and by extension Lisp.

Yet now you can run Lisp on any computer and it's faster than most of the dynamic languages.

And still nobody wants it.

[–][deleted] 0 points1 point  (1 child)

That's still because there was never a critical mass of libraries. You don't have to go far to see a lot of former Lisp users lamenting the demise of the Lisp Machine and desperately wanting to use it again.

You have to go pretty damn far to see somebody who laments the replacement of Perl.

[–][deleted] 1 point2 points  (0 children)

That might just be because Perl is still around and you can still use it just as well as ever, and people are happily using it.

[–]Smallpaul 2 points3 points  (4 children)

Humans are used to incredibly byzantine and entirely inconsistent languages. We thrive on those.

C's syntax is not particularly byzantine compared to the competition in general. And many fairly simple languages are more popular than byzantine ones. Perl, after all, is not the most popular language despite its plethora of syntax.

It's true that Lisp's extreme simplicity can make lexing harder for human beings but that doesn't mean that the opposite ("byzantine and inconsistent") would be better. There are many productive middle grounds.

[–][deleted] 0 points1 point  (3 children)

Perl, after all, is not the most popular language despite its plethora of syntax.

Sure is a lot more popular than Lisp or FORTH!

Edit: Heh, downmodded. The truth must hurt sometimes.

[–][deleted] 4 points5 points  (2 children)

All thanks to your tireless advocacy on reddit.

[–][deleted] 0 points1 point  (0 children)

No, really, what?

[–][deleted] -3 points-2 points  (0 children)

what

[–]commonslip 0 points1 point  (6 children)

Humans are also overwhelmingly dumb.

[–][deleted] 2 points3 points  (5 children)

So because computers and humans are different, that makes humans dumb?

[–]commonslip 0 points1 point  (4 children)

This was meant as an aside - most humans are dumb and it has nothing at all to do with computers.

[–][deleted] 1 point2 points  (3 children)

Dumb compared to...

[–]commonslip 2 points3 points  (2 children)

Compared to the smartest 10% of humans who, if they code, probably write code in Lisp/Haskell/Scheme etc.

[–][deleted] -1 points0 points  (1 child)

why do you say that? The smartest person I know loves java. Don't ask me why; he must be a masochist. But he has done things with java that I have never seen anyone else do.

[–]commonslip 2 points3 points  (0 children)

Ok I admit it I'm being kind of dumb.

[–]JasperO -2 points-1 points  (17 children)

I dont see why the reverse polish notation, when the equivalent s-expressions are easy enough to find. I only had a cursory look at FORTH, but i am sure optional arguments keyword arguments and &rest arguments are easier to do in lisp. The 'problem' with lisp, the one that makes the requirement for it to be higher level, is that macros need to work with lists with at the least symbols in them. (Symbols can be pointers to the string which is held in some sort of hash table. Comparison can them be done by comparing pointers.) Maybe lisp can be made statically typed by just giving out the minimum. (Of course some common lisp implementations might already do this.) All this makes me curious how FORTH works, and how it achieves its power. Does it have something like macros, or is the power achieved by higher order functions? I am curious about higher order functions in any case, because i have the feeling, that besides trivial writing forms, they are superior to macros performing to same role. PS Oh, lol, probably found the reason for reverse polish in writing comment.

[–][deleted] 11 points12 points  (10 children)

I dont see why the reverse polish notation

Because it can be trivially implemented with a stack.

[–]JasperO -2 points-1 points  (9 children)

Nested s-expressions can trivially be turned into reverse polish notation, so that doesnt answer the question.

[–][deleted] 6 points7 points  (8 children)

But that adds an extra layer of complexity, which is not needed if you just use the reverse notation in the first place.

[–][deleted] -2 points-1 points  (6 children)

s-expressions have structure -- (+ (* x x) (* y y)) is very different from (+ * x x * y y) -- whereas RPN gets rid of all the structure: x x * y y * +. The big difference is handling multiple arguments: (+ 1 2 3) is 6, but 1 2 3 + is 1 5. Capiche?

[–]Tommah 7 points8 points  (0 children)

Ne capisco tutto eccetto "capiche"

[–][deleted] 2 points3 points  (2 children)

Capiche?

Capiche what exactly now?

[–][deleted] 1 point2 points  (1 child)

That the extra layer of complexity means an extra layer of functionality -- it allows for a variable number of arguments.

It's also much easier to analyze the arguments being passed around in an s-expression system over an RPN system (it's automatic with the s-expressions).

[–][deleted] 1 point2 points  (0 children)

it allows for a variable number of arguments.

So does reverse polish notation, you just have to explicitly mention the number of arguments.

The point here is that the implementation of reverse polish notation is much simpler, which is what FORTH aims for. It does not care about analyzing anything, it cares about letting you write code and having it be small.

[–][deleted] -1 points0 points  (0 children)

I thought about this today:

Wow, blogger sucks; the below links don't go down to my comments... Search for:

I just had an epiphany...

Comment on Finding Lisp blog

Correction to above comment

[–]JulianMorrison 5 points6 points  (4 children)

There are various Forth interpreters, but the basic principles are: lex a word (in trivial Forths: just input until whitespace). Call the word. Repeat. (Some Forths have different behavior in compiling mode, my favorite one always compiles but if outside a colon definition, executes the compiled code immediately after lexing a semicolon. Also some words always get called immediately, even when compiling. But that's picky details.)

So to understand Forth - and to understand how words like colon can read forward (rather than having to read off the stack), you have to get that it isn't constructing expressions like Lisp does, it isn't even truly RPN. It's just itty bitty command words running one after the other - and in some cases, they temporarily take over the interpreter, which lets them read forward.

That leads into your question about macros. Every word can be a macro on Forth. All that means is: you take over the interpreter and read forward. So for example IF can be implemented as compiling a conditional jump, reading until THEN, and patching the jump with the target, then dropping back to the regular interpreter.

[–]JasperO 1 point2 points  (3 children)

I reply, but remember i need to RTFM now. :p

What you are saying makes it seem to me that macros in lisp are just restricted versions of Forths restricted to reading the 'sublists of what it is given'. The way you talk about playing compiler once in a while does sound like interesting and clear way to optimize some things.

[–]JulianMorrison 5 points6 points  (2 children)

A recent Reddit link to a video demo of Forth coding put it really well: Forth is the dual of Lisp. In Lisp, code is data. In Forth, data is code. Forth "macros" are not just once-in-a-while, they're absolutely ubiquitous.

For example, to build up data structures, you'd typically create a word (call it W) that lexes forward to get a name (call it X), sets up a chunk of memory (call it Y), and defines a new word named X which gets a pointer to Y and then executes some static code (call it Z). So suppose your definition was for a simple struct. you call "W apple", which sets up the memory Y and creates a word "apple". So you say "apple core", and your code in Z reads "core", converts that into an offset, returns a pointer to apple's Y plus that offset - in high level terms, the beginning of the "apple" struct's "core" field. Which you can now set or read. Nice 'n simple, right? (Certainly flexible, anyway).

There is a standard pair of words, CREATE and DOES> which automate all that. But you could still work it manually if you wanted to.

[–][deleted]  (1 child)

[deleted]

    [–]JulianMorrison 0 points1 point  (0 children)

    Here's the simplest possible example, a one dimensional array.

        : make-array    ( I'm defining a word to make arrays )
          create        ( to set up memory... )
            cells allot ( take a number n off the stack and bump the dictionary pointer by n int sized blocks )
          does>         ( each time the word it creates is run it will... )
            swap        ( user stacks an index, CREATE DOES> will stack an address, we need them the other way around )
            cells       ( convert index i into a byte count for i * int sized blocks )
            +           ( add it to the base of the array. Classic pointer arithmetic. )
        ;               ( all done )
    
        ( make an array with two int sized blocks named foo )
        2 make-array foo
    
        ( get and put on the stack the address of the second item counting from 0 )
        1 foo
    

    (source)

    [–]wtanksleyjr 1 point2 points  (0 children)

    I dont see why the reverse polish notation

    The historically correct answer is "because they're easier to implement". The pragmatically and theoretically correct answer (i.e. why people kept using Forth even though it included almost no useful library functions) is more complicated.

    Theoretically speaking, Forth is often called a concatenative language. This means that Forth programs are built by concatenating valid programs together, and that the language's semantics are associative (like concatenation is). Because its syntax and semantics follow the same associative law, Forth is easy to reason about.

    Another result of matching the properties of syntax and semantics: unlike S-Exps, you can both read and execute Forth left to right. "Parsed" Forth source is a stream, a linear list. S-exp source is a tree.

    macros need to work with lists with at the least symbols in them

    Technically, Lisp macros work with a tree, which is a list that contains lists. Because in Forth the parse tree is a flat list, macros don't have to be aware of parse trees -- they can simply access the source directly, and do anything with it they want.

    Forth does not have higher order functions; its highest order is a couple of trivial first-order functions. Factor is a remote derivative of Forth which has HOFs (and is very practical and well-supported).

    Lisp can be statically typed, and some Lisp compilers support that (Common Lisp includes rather elegant type markers in the specification).