Live data from Hacker News

Easy Forth (2015)

skilldrick.github.io

111–120 of 128 posts

Re: Easy Forth (2015)

#111
post #14

Forth is very enjoyable, and it's always exciting to see someone new discovering it, but it has three big problems. The first is a technical problem: the forte of Forth is self-hosted developer tooling in restricted environments: say, under 256KiB of RAM, no SSD, under 1 MIPS, under 10 megabytes of hard disk or maybe just a floppy. In that kind of environment, you can't really afford to duplicate mechanism very much,…

Very much this. Even when programming for constrained environments, it's almost never necessary to self-host anymore. It's easy to use host-side tools to crunch code down to something that'll work on whatever the target is.

From a practical standpoint, one of the few modern uses where FORTH shines is as a REPL for new chips/SOCs so you can play around with the hardware and see how things actually work/debug the databook.

Re: Easy Forth (2015)

#112
post #14

Forth is very enjoyable, and it's always exciting to see someone new discovering it, but it has three big problems. The first is a technical problem: the forte of Forth is self-hosted developer tooling in restricted environments: say, under 256KiB of RAM, no SSD, under 1 MIPS, under 10 megabytes of hard disk or maybe just a floppy. In that kind of environment, you can't really afford to duplicate mechanism very much,…

Very much this. Even when programming for constrained environments, it's almost never necessary to self-host anymore. It's easy to use host-side tools to crunch code down to something that'll work on whatever the target is. From a practical standpoint, one of the few modern uses where FORTH shines is as a REPL for new chips/SOCs so you can play around with the hardware and see how things actually work/debug the datab…

Have you been using it for that? Which Forths and which chips have you been using?

Re: Easy Forth (2015)

#113

Earlier quoted context omitted.

Reading lines from a file and handling the strings in memory is what made me stop using it after a 3rd day of advent of code one year. I simply couldn't find a good solution, without a massive excursion into how to use the pad. Such a supposedly simple thing like reading a complete line from a file, yet it stopped me completely. Of course I could have "cheated" and put the input right into the program, but I wanted t…

One year (2022) I could see, on an early problem (day 2), that I could define a handful of words in forth such that I could execute the (modified) input file itself as code (there were only 9 possible combinations since it was rock-scissor-paper, although I did have to alter the input by removing the spaces first, like "A X" was changed to "AX") to get the answer. I defined words that matches the 9 inputs and had tho…

That's a great idea!

Re: Easy Forth (2015)

#114
post #40
post #33

Earlier quoted context omitted.

Every single coder that uses chaining operators is using concatenative programming concepts. Shell piping is also a form of concatenative programming. Just because you don't specifically use forth does not mean forth is dead.

Shell piping isn't Forth.

I didn't say it was forth, I said it was concatenative.

Forth itself is hard to categorize since it refuses to standardize but we all know what it looks like, I'd say its a low level language/VM that manages everything through stacks (usually 2) there's forthlike languages and also concatenative languages. concatenative languages can be far removed from forth, I don't mean that the shell itself is concatenative, but only the shell pipelining aspect, which you can imitate in any forth. take an object and keep passing it to subsequent functions without popping that know s how to handle that object, that's a shell pipeline to me, all of unix can be passed the /dev/std* objects and they can all modify it and pass it along to the next function/program.

https://concatenative.org/

Re: Easy Forth (2015)

#115
post #114
post #40

Earlier quoted context omitted.

Shell piping isn't Forth.

I didn't say it was forth, I said it was concatenative. Forth itself is hard to categorize since it refuses to standardize but we all know what it looks like, I'd say its a low level language/VM that manages everything through stacks (usually 2) there's forthlike languages and also concatenative languages. concatenative languages can be far removed from forth, I don't mean that the shell itself is concatenative, but…

Well, I agree that Forth is concatenative (like stack languages in general), and so are shell pipelines.

But you said, "Just because you don't specifically use forth does not mean forth is dead," and unless I misread your intent, you included your shell-scripting point on the theory that it was relevant to that question: whether or not Forth was dead. The implication seemed to be that, as long as people were using shell pipelines, Forth wouldn't be dead. But that's wrong; Forth could be totally dead while other forms of concatenative programming were alive and well.

Re: Easy Forth (2015)

#116
post #14

Forth is very enjoyable, and it's always exciting to see someone new discovering it, but it has three big problems. The first is a technical problem: the forte of Forth is self-hosted developer tooling in restricted environments: say, under 256KiB of RAM, no SSD, under 1 MIPS, under 10 megabytes of hard disk or maybe just a floppy. In that kind of environment, you can't really afford to duplicate mechanism very much,…

Forth has always intrigued me as one of those languages (APL and Mumps also come to mind) that appears to have a superpower, for example expressing somewhat complex systems compactly, while at the same time also being flawed enough so that this superpower only appears to be applicable to a small niche.

Given the somewhat sorry state of (lack of) expressiveness and accompanying bloat in programming in general, it would be really interesting to see if that is inevitable, so if the superpower is in fact also the flaw, or if it's possible to extract the superpower from the flaw.

The way you express Forth's superpower is one I haven't seen so far and seems to point a possible way:

> So you end up using the same mechanism for fairly disparate purposes, with the attendant compromises.

Can you tell more about those mechanisms that are used for disparate purposes?

> If it's ever easier to write something in Forth than in C, it's probably because you can define immediate words, thus extending the language into a DSL for your application in ways that are out of reach of the C preprocessor.

So compile-time metaprogramming is not just available as an add-on, but very much "how things are done"?

https://www.forth.com/starting-forth/11-forth-compiler-defin...

And having a bit of compile-time metaprogramming also be the compiler is enabled by effectively not having syntax?

Re: Easy Forth (2015)

#117
post #67

Earlier quoted context omitted.

The description of F83 sounds interesting - any way I can see it in action, or use it on my own?

Sure, I git cloned my copy from https://github.com/ForthHub/F83 , and it runs fine under DOSBox. If you have Git and DOSBox installed, I think you can just type git clone https://github.com/ForthHub/F83 cd F83 dosbox . f83 : fish 0 do i . ." fish" cr loop ; 7 fish

Thanks! I'm using this as a guide https://www.forth.org/OffeteStore/1003_InsideF83.pdf. See you in the next forth thread :)

Re: Easy Forth (2015)

#118
post #82

Earlier quoted context omitted.

> My problem is that I cannot see how control flow works in Forth, e.g. a simple if-then-else. figuring this out for my own FORTH interpreter was a moment i still remember, nearly 50 years later. quite a revelation

In my opinion, a language that requires a programmer to have a "revelation" to understand basic control flow is not a language that is useful or practical for solving real world problems. I would prefer to write in assembly language than write in Forth. Which is what I have done with one of my current projects. With assembly language, there is a good chance that a random person with some minimal programming skills wo…

It's a revelation to understand how basic control flow is implemented in any compiler. From your described preference to not learn things that aren't generally known, it's a safe bet that you don't understand CPS or SSA either, or know what a basic block is.

Re: Easy Forth (2015)

#119
post #14

Forth is very enjoyable, and it's always exciting to see someone new discovering it, but it has three big problems. The first is a technical problem: the forte of Forth is self-hosted developer tooling in restricted environments: say, under 256KiB of RAM, no SSD, under 1 MIPS, under 10 megabytes of hard disk or maybe just a floppy. In that kind of environment, you can't really afford to duplicate mechanism very much,…

Forth has always intrigued me as one of those languages (APL and Mumps also come to mind) that appears to have a superpower, for example expressing somewhat complex systems compactly, while at the same time also being flawed enough so that this superpower only appears to be applicable to a small niche. Given the somewhat sorry state of (lack of) expressiveness and accompanying bloat in programming in general, it woul…

I agree about Forth being a fatally flawed language with superpowers, although I think we could easily have ended up in a world where Forth played the role of C, which has its own fatal flaws.

Yes, compile-time metaprogramming is very much "how things are done". This is simplified by not having syntax, but I don't think they're inseparable; you could imagine building up a compiler in the same way from an almost-as-minimal base using something like https://jevko.org/, S-expressions, a Prolog-like extensible infix parser, or a Smalltalk-like non-extensible infix parser with an open set of operators. I think most of these would be improvements. PostScript has an only slightly more elaborate syntax than Forth, but uses Smalltalk-style lightweight lambdas (called "quotations" in several other stack languages) to provide control-flow operators through runtime metaprogramming instead of compile-time metaprogramming.

As for "mechanisms used for disparate purposes", for example, the outer (text) interpreter in typical Forths plays the role of the Unix shell, the C-level systems programming language, the assembler syntax, and the user interface to applications such as, traditionally, the interactive text editor. And in https://news.ycombinator.com/item?id=45340399 drivers99 reports using it to parse an input file. The Forth language is not a very good shell command language, not a very good high-level programming language, and not a very good text editor user interface language, but it's adequate for all of these purposes.

The dictionary, similarly, serves to hold definitions for all those purposes. But it also allocates memory in a region-allocator-like way—a byte at a time, if need be. You can use the same words like , to store data into the dictionary directly, in interpretation state:

    create myarray 3 , 4 , x ,
Or in a constructor:

    : throuple create , , , ;  3 4 x throuple myarray
In traditional Forths like F83, , is also the mechanism for adding an xt to a colon definition, but in ANS Forth compile, was added as a possible synonym which would also permit writing Forth code that was portable to non-threaded-code implementations. https://forth-standard.org/standard/core/COMPILEComma

The operand stack serves to pass arguments and return return values, as well as to hold temporaries, but you can often use it to store a local variable as well, and space on it is dynamically allocated, so it's possible to use it to pass or return variable-sized arrays by value. At compile time, it's used to keep track of the nesting of control-flow structures.

The return stack serves to store return addresses, but also to store loop counters or maybe another local variable. And return-stack manipulation provides you with a relatively flexible form of runtime metaprogramming for things like stackless coroutines, shallow-bound dynamic scoping, and exception handling. Here's an implementation of dynamic scoping (which cannot be used inside a do loop or when you have other stuff on the return stack):

    0 value old  0 value where  : co 2r> >r >r ;
    : let! dup to where  where @ to old  !  co  old where ! ;
Example usage:

    decimal : dec. 10 base let! . ;
This temporarily sets base to 10 before calling ., but then restores base to whatever value it had before upon return. A better implementation that uses the return stack instead of old and where to save and restore the values is

    : (let!) dup @ over swap 2r> rot >r rot >r >r >r ! ; : let! (let!) 2r> ! ;
(This is probably not very understandable, but I've written an 1800-word explanation of it elsewhere which you can read if you like.)

Pointer arithmetic and integer arithmetic are the same operation, as they are in most untyped languages. This is different from C, where they are done with the same operators which are implemented differently for integers and for different types of pointers.

The "filesystem" in traditional Forths simply exposes the disk as an array of 1024-byte blocks which could be mapped into memory on demand. Conventionally you would divide your code into 1024-byte screenfuls, each space-padded out to 64-character lines, 16 of them. In effect, each screen was a different "file", identified by number rather than name. It's reasonable to argue that this is not a very good filesystem, and not a very good format for text files, but to implement any filesystem on top of a disk or SSD, you need a layer that more or less provides that functionality; all that's required to make it usable for code blocks is to use 1024-byte blocks instead of 128-byte or 512-byte or whatever.

Multitasking in traditional Forths is cooperative. In some sense this eliminates the need for locking; for example, to ensure that the block buffer you've mapped your desired block into doesn't get remapped by a different task before you're done using it, you simply avoid calling anything that could yield. Unfortunately, Forth doesn't have colored functions, so there's no static verification that you didn't call anything that calls something that yields. Cooperative multitasking is sort of not very good multitasking (since an infinite loop in any task hangs the system) and not very good locking, but it does serve both purposes well enough to be usable.

Scheme is sort of like this too; famously, Scheme's lambda (roughly Forth's create does>) is semantically an OO object, a statement sequencing primitive, a lazy-evaluation primitive, etc., while S-expressions are a similar syntactic cure-all, and call/cc gives you multithreading, exception handling, backtracking, etc. See https://research.scheme.org/lambda-papers/. In practice a small Lisp is about the same amount of code as a small Forth.

BTW, I still have a paper of yours in my queue to read!

Re: Easy Forth (2015)

#120
post #67

Earlier quoted context omitted.

Sure, I git cloned my copy from https://github.com/ForthHub/F83 , and it runs fine under DOSBox. If you have Git and DOSBox installed, I think you can just type git clone https://github.com/ForthHub/F83 cd F83 dosbox . f83 : fish 0 do i . ." fish" cr loop ; 7 fish

Thanks! I'm using this as a guide https://www.forth.org/OffeteStore/1003_InsideF83.pdf . See you in the next forth thread :)

Dr. Ting's book is indeed excellent, but I've learned more from experimentation and from digging into the code than from reading it.
Post reply on HN