
Forth implemented in Rust trait system - Ashymad
https://github.com/Ashymad/fortraith
======
crazypython
I don't see why people won't just take the step D and Lisp do-- allowing full
use of the programming language at compile time.

You can execute an ordinary functions at compile-time to read a DSL from a
string or read attributes (reflective metaprogramming) on your program's
classes. Take the string it outputs, use mixin(), and you have code. For
example:

    
    
        // Sort a constant declaration at Compile-Time
        enum a = [ 3, 1, 2, 4, 0 ];
        static immutable b = sort(a);
    

"a" only appears in the compiler's memory. "sort" is a normal function that
runs at compile-time. "allowing accessto the full language at compile-time" is
similar to what dynamic languages such as Python and JavaScript give you,
except D is a static language with GCC and LLVM backends.

~~~
ncmncm
The most useful values at compile time are types, so straight-up interpreting
the core language at compile time is not enough. You need meta-typed named
values to transport types in, and meta-functions to pass them to.

Fortraith cleverly re-purposes existing features, doing some violence to
language usage conventions to achieve it.

~~~
dependenttypes
> so straight-up interpreting the core language at compile time is not enough.
> You need meta-typed named values to transport types in, and meta-functions
> to pass them to.

Can you please explain what you mean by this?

~~~
neutronicus
In Rust (for example), Types are not Values. You can't store them in
variables, pass them to functions, etc.

However, at macro-expansion time, often what you want to do is examine a Type
and expand the macro differently based on some information about the Type.

So you would like your Macro language to have some notion of manipulating
Types that is absent from the language itself

------
frompdx
Definitely interesting, but I don't see any mention of being able to use this
interactively or incremental compilation, which is what makes Forth, Forth.
Forth isn't just syntax. It's an operating system and a programable
programming language.

~~~
megameter
The term "concatenative language" fits better for adaptations of Forth that
also discard major semantics of Forth. There is a holistic quality to Forth
that results in a lot of idioms that are not obvious, and concatenative
systems that deviate from the whole tend to fall into an unexplored territory.

For example, in CASE ... OF ... ENDOF ... ENDCASE, the input value is consumed
when OF is entered. But this means that the default result, positioned before
ENDCASE, has to move the input value to the top of stack so that it can be
consumed before the result. The examples in the ANS standard prefer using >R
... R> as a scratchpad for this purpose, so that any number of results may be
pushed into the data stack, while the input is moved onto the result stack and
then pushed back to the data stack. But the whole existence of the return
stack and words that use it is a curious detail that doesn't come up if you
start from an RPN calculator instead of a complete Forth system. Someone
writing a RPN system in an applicative language, upon seeing this semantic,
might be tempted to beef up the syntax rather than add this idiom. And in
Forth this idea likely was only arrived at through the numerous iterations
Moore made to achieve better expression in fewer words, since the return stack
is useful everywhere.

~~~
Ashymad
You got me. I was too lazy to implement the return stack. But it should be
fully possible. The hardest part was not implementing things in the trait
system, but parsing any non-trivial syntax using the clunky macro_rules!. For
this reason if/else/then are not a special syntax but words that block and
unblock subsequent word execution.

------
fmakunbound
This is a pretty superficial treatment of Forth. It's more of a simple RPN
calculator than a Forth.

------
ncmncm
This is brilliant! Equivalent, in its way, to C++ template metaprogramming. It
was cheeky to do a Forth instead of an ML. The traditional way to demonstrate
TC is by sieving primes at compile time.

C++ is actively replacing its compile-time ML with core language features, but
isn't there yet. Still, it has been many years since I needed to code any of
my own TMP.

~~~
bonzini
Sort of, arithmetic is implemented (through the trait-eval crate) from the
Peano axioms. Probably it is not very fast, even in comparison to C++
standards.

~~~
Ashymad
Indeed, could possibly be sped up by using typenum[1] instead of trait-eval,
as it is not Peano axioms based.

[1] [https://docs.rs/typenum/](https://docs.rs/typenum/)

------
andylei
> Rust's trait system is Turing complete

has anyone tried implementing rust in rust's trait system

~~~
saagarjha
Turing complete≠uses the syntax of your favorite programming language.

~~~
_bxg1
Any Turing-complete system can do anything a general computer can do, which
includes compiling your favorite programming language.

~~~
saagarjha
No, that's not what Turing complete means. Turing complete means it can do an
arbitrary computation, but "implementing Rust" usually means it needs to be
able to take in a string of code and produce a binary, which means your
program needs to have some way of actually doing that. Sure, you can encode
the compiler into the Turing machine, but an arbitrary Turing-complete tarpit
may not actually have the syntax to know what a string is. Usually the best
you can do is encode the programming language into some form the machine can
understand. (For example, with Fractran you'd encode your input as some sort
of Gödel numbering before giving it to the program.)

~~~
jfkebwjsbx
Compiling _is_ an arbitrary computation.

Encoding the inputs/outputs for a given TC system may be a pain, but that is
irrelevant to expressiveness power.

~~~
saagarjha
Right, I'm not saying you can't put the compiler for the encoded input/outputs
into the machine or that it's not expressive enough. I'm just saying that
you'll have to encode stuff, it's not like traits somehow can magically give
you a "compileToRust()" function that you pass the unmodified code into.

~~~
jfkebwjsbx
Yeah, but when someone mentions some system is TC they are not claiming
input/output is easy to encode.

In fact, in most cases, when you hear the TC claim it is about an exotic
system :)

------
unixhero
Wow that's what I call an emergent property!

------
mrlonglong
Sick! :-)

------
jerf
Finally, Rust is production-ready.

It is neat to see something more practical than an Brainf* interpreter.

~~~
ptspts
A list of even more practical pieces of production code in Rust:
[https://wiki.mozilla.org/Oxidation#Shipped](https://wiki.mozilla.org/Oxidation#Shipped)

~~~
saagarjha
I suspect you missed the /s

