Play: Statically typed Forth, compiled to WASM
play-lang.dev
play-lang.dev
In Forth a compiled word definition begins with : and ends in ; while Play definitions begin at :def, use : to separate signatures from word bodies, and appear to be implicitly terminated wherever the next definition begins. Forth definitions always appear in "reading order"- words are declared before they are used- but the very first example on the Play home page inverts this convention. It feels rather like reading pig-latin, or perhaps ML wearing a Forth-skin-suit.
Forth's hybrid compiled/interpreted nature is at the heart of its expressiveness; so far as I can tell, this is entirely absent from Play. How would I define a word like "when:", "def:", or "["?
In my opinion it would be clearer and more accurate to describe Play as simply a concatenative functional language.
Forth also did serve as the true inspiration for Play, so it makes sense to me to put that front and center.
Forth-based languages was the closest I could come to that experience, but most of those languages did not have all the niceties I've come to enjoy, like strong static typing and purity.
I also wanted a language which would work equally well on the backend as the frontend, and with wasm this seemed possible.
So those were the initial ideas behind the project.
I'm in a similar boat, I find the pipeline-style code to be the most pleasant and use ->, ->>, cond->, some-> very heavily in my Clojure code and I actually spent a few months with Factor before I got into Clojure.
For large chunks of my code, I find the concatenative style an excellent fit, but the remaining parts where I have to juggle the stack ruins the experience for me. I really don't want to drop, dup, rot or whatnot.
I've always wondered if there wasn't some way of making a concatenative language that naturally didn't require stack operations like that, but I haven't tried too hard to figure it out (or check if anyone else has). I guess something that might work is to combine concatenative "statements" with something like let bindings and destructuring, so you can destructure your stack to extract the stuff you need, binding them to names to be used elsewhere.
I have a question the planned Alpha 7 feature: "smaller than 32-bit values (char/byte)" - I'm so used to bytes being a fundamental primitive in programming languages that it's hard for me to imagine not immediately having access to them.
Can you explain a bit why this is non-trivial, and what the implementation is going to look like?
> I'm so used to bytes being a fundamental primitive in programming languages
Sorry to hijack the question, but tangentially, this actually used to be very unusual.The B language, C's predecessor, did not have a char data type. Or int, either. Only a single type -- a 16 bit word then.
At the time, most computers used word addressing exclusively, so you couldn't directly access bytes, only words.
This is also why some early computers could easily be e.g. 36 bit machines, like the PDP-10.
C was, thus, an extension of B(CPL) to allow both words and bytes, or "char"s, using the PDP-11's brand new byte addressing. (among other additions like structs)
Fossil doesn't support basic code review and merge requests though (like Github PRs). Actually it kinda does through bundles, but Github would probably be better for that use case. Don't think it will be a problem any time soon for this project, though.
All in all, I've used Fossil for about a year and I'm pretty happy with it.
Links:
* (StrongForth) http://www.arestlessmind.org/2009/02/03/intro.html
* (Kitten) https://kittenlang.org/
There are so many projects I started because I was interested in the problem set, got to a point where I was proud of the result, only to change my search terms just a little and find an established project by someone else.
And sometimes I read replies like this and I think it feels like someone just saying "repost: " and linking fifteen other HN threads.
As for Kitten, I didn't like the syntax. To me the interesting thing about Forth-like languages is the postfix/rpn syntax, which Kitten moves to far away from. I really liked how `if` in Factor was just a postfix word like any other, where the then- and else-clause was just quotation arguments.
I'm sure Kitten is a fine language, it just wasn't what I was looking for.
It is a rather restricted and "high level" language and has a nice, human readable, s-expression text format (WAT). For example it is perfectly reasonable to write WAT by hand after learning the basics.
Also there is plenty of fantastic, modern documentation, tooling and specification around WASM.
If you want to create a language that can run in browsers, you either need to target js or wasm. Wasm seemed like the better fit (i’m done with 53-bit ints), so I googled everything on that.
Read a book on GC (wasm has no such thing built in), read two books on Forth (after being intruiged by its syntax), Learned about compilers by looking at Elm source code.
I guess I’ve been around so many languages that it’s impossible not to form an oppi ion on what makes a good language, so once I knew the basics it was difficult to avoid making my own.
Ooo la la! How was that?
Compilers are really just pure functions of String -> String/Bytes, so a pure functional language is a pretty good fit.
Besides, I know Elm like the back of my hand. I’d probably write in Elm even if it was a poor fit.
I'm working with Joy using Prolog and it's dreamy. I just started to work on a compiler (until I got sidetracked) so I'm going to read your code with interest. (I thought about WASM as a target but I'm not trying to make a real language.)
I.e., if I have user input that might put different things on the stack depending on the input.
In the first case, no, but I see the utility and might add it in later.
In the second case: probably. This is Alpha 1, after all,
In the example you mention, Play would infer that the code places a Union on the stack, and would require a multi-word (pattern matching word) to deal with it later.