This is incredible. I'll be tinkering with this for a while, guaranteed. As the advantages of combining Lisp and Forth in this way are slowly revealed to me it's like unlocking parts of my brain to interact with each other that never have done before.<p>Pretentiousness on my part aside, this is a pretty mind-blowing concept. The interpreter being in less than 1000 lines of (comprehensible) C is all the more commendable (most of these minimal languages turn out to be some monolithic Rust thing or similar, which kinda defeats the entire purpose imo).<p>Excited to take a closer look at the source to see how the various data structures etc. are laid out in memory. I won't be able to resist making comparisons to my current/other favourite mini-language 'fe' (<a href="https://github.com/rxi/fe">https://github.com/rxi/fe</a>), a sub-1000-line Lisp also written in C. If you haven't seen that one I'd definitely recommend checking it out.<p>Thank you for putting this online. Happy hacking!
Very cool. I like that both lisp and forth were “discovered” and that this cvbp is more fundamental than both(?!). This reminds me of [pdf] <a href="https://dl.acm.org/doi/pdf/10.1145/181993.181999" rel="nofollow">https://dl.acm.org/doi/pdf/10.1145/181993.181999</a> and wonder if/how it relates.
What I like about this is how neatly it reduces everything to a small set of concepts. Much like lisp and forth, but not the same as either. It's exciting to think that there may be more of these out there, waiting to be discovered!
Reading the example, I really wish the syntax for push and pop had been "<foo" (push foo on stack) and ">bar" (pop from stack into bar). I find the choice of $ and ^ not obvious. Especially since, for me, ^ implies popping, not pushing.
This looks really neat, although I'm still wrapping my head around it! It's funny how things that are even more fundamentally simple than what has been discovered, can be (initially) harder to reason about!<p>So you could presumably also write a Lisp interpreter AND a Forth interpreter using it?<p>(Might as well write a Turing machine interpreter too for the trifecta... assuming one can decide on the syntax...)<p>That plus some additional functionality to make it more usable in the general sense (adding math functions, string manipulation, maybe some basic I/O) and it might be a VERY interesting instructional tool.<p>I've heard the term "thunk" but I forget what it means...
What has Lisp semantics and a stack with "call by push value" and whatnot is any one of the stack-based virtual machines used for compiling Lisp over the past 60 years.
Another recent attempt at a language combining features of Forth and Lisp <a href="https://github.com/rickardnorlander/misc/tree/main/cursed_lang">https://github.com/rickardnorlander/misc/tree/main/cursed_la...</a><p>Someone even asked the same question<p><pre><code> ' seems redundant. 'x could just be (x)?
</code></pre>
though for that language the answer was that yes it's exactly the same.
Cool language. One modest suggestion: perhaps return 0 rather than 1. Feature request: addition and division as well as subtraction and multiplication ;)
Reminds me of the language from this paper, which also shows how to smoothly integrate I/O and state into such a style <a href="https://arxiv.org/abs/2212.08177" rel="nofollow">https://arxiv.org/abs/2212.08177</a>
If you like to work the other way I present <a href="https://github.com/garlic0x1/forth">https://github.com/garlic0x1/forth</a> forth in common lisp.
Wow he even provides an interpreter in C. How would a compiler implementation for this language foreseeably differ from the interpreter given, does anyone know? Trying to learn about this more.
Since it is written in C, we need to write COBOL and FORTRAN interpreters with it, make sure the manpages are in Latin, and we'll hit the ancient languages nerdvonia.
I've never really got Forth. It's good for sending commands to a printer, but actually programming in it seems like a drag. I get that it's technically the same as lisp code, just backwards without the parens, but adding the parens just makes it easier to understand. Adding variables is smart and would make it more tolerable but I would still rather work in lisp.
Hmm, really nice! I might have to steal all of this for my language (<a href="https://github.com/alexisread/minim/blob/develop/minim/minim.org">https://github.com/alexisread/minim/blob/develop/minim/minim...</a> really in flux ATM)<p>Reminds me of <a href="https://pygmy.utoh.org/3ins4th.html" rel="nofollow">https://pygmy.utoh.org/3ins4th.html</a> except the third instruction is execute rather than quote.<p>In the spirit of building from scratch, I'd like to highlight sectorforth/milliforth (<a href="https://github.com/fuzzballcat/milliForth/blob/master/sector.asm">https://github.com/fuzzballcat/milliForth/blob/master/sector...</a>) - they implement as little as possible to get a working system ie. just the basic fetch/store ops, numerical and I/O.<p>The parser can probably be reduced - there's a nice paper detailing Cognition (a forth dialect, but the parsing could be broken out into a lib - <a href="https://ret2pop.nullring.xyz/blog/cognition.html" rel="nofollow">https://ret2pop.nullring.xyz/blog/cognition.html</a>) where using a couple of crank operators, you can implement custom syntax in a forth-style way (as opposed to say PEGs).<p>In terms of variables and scoping, Dreams (another forth dialect- <a href="http://elilabs.com/~rj/dreams/dreams-rep.html" rel="nofollow">http://elilabs.com/~rj/dreams/dreams-rep.html</a>) uses mianly dynamic scoping, and builds it's structs (C-style structs) using the standard forth struct words. This allows it to be hard-realtime though as you don't need to walk the lexical tree to bind variables. You can also early bind like with CBPV. I guess this is also similar to REBOL's BINDology (<a href="https://github.com/r3n/rebol-wiki/wiki/Bindology">https://github.com/r3n/rebol-wiki/wiki/Bindology</a>)<p>Lots of overlap here with these things. Just for completeness there's also dynamic variable handling (over lexically scoped structures) with wat (<a href="https://github.com/GiacomoCau/wat-js/tree/master">https://github.com/GiacomoCau/wat-js/tree/master</a>) though this is not realtime.<p>Is it possible to make the closures dynamically scoped by default here? I've not had time to think about this properly. I like the fact that eval is lazy here like in forth or REBOL, rather than eager as in lisp - the idea of passing around blocks/thunks appeals wrt realtime (well with dynamic scoping) and parallelism.<p>The env per-thread I guess could be compared to the forth dictionary? Dreams abstracts this by virtue of it's (token) threading model which appears useful for task switching, objects and the like.<p>I'd also like to highlight able forth which has:
Compiler-only design (like Freeforth)
- Word-classes (like Retro)
- A straightforward bootstrap process using a minimal set of seed words (like seedForth)
- No (ZERO) special forms, not even integers, and a consistent model for adding literals without the complexity of i.e. recognises
- A single flat word-list that can be freely manipulated and composed of other word-lists
- No separate [assembly] code words
- Explicit optimizations (ONLY) i.e. explicit tail-call elimination<p>I've only started looking into able forth so can't really comment on it much, but the no-special-forms appeals here.<p>Sorry, random thoughts here, I'd like to discuss further when I've had time to digest your language. :)
> <i>It's a hybrid language combining Forth and Lisp, so naturally it's called Forsp</i><p>Shame. Missed a golden opportunity to call it "Lithp" :)