Live data from Hacker News

Forth implemented in Rust trait system

github.com

31–40 of 91 posts

Re: Forth implemented in Rust trait system

#31
post #10
post #5

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.

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.

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/

Re: Forth implemented in Rust trait system

#32

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,…

> 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. Because "full use of the programming language" implies Turing completeness, which means compilation may require unbounded time and compute resources. You can allow use of a non-Turing complete subset, and this is something that dependently-typed languages can do quite elegantly.

A program that requires 2^256 time units and 2^256 memory units is not really any better compared to unbounded computations.

Re: Forth implemented in Rust trait system

#33
post #9

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,…

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.

> 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?

Re: Forth implemented in Rust trait system

#34

Earlier quoted context omitted.

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

Incorrect. Turing completeness means using the syntax of your favorite programming language is "merely" a matter of writing the appropriate program. What GP is proposing is completely impractical, of course. But not unreasonable, and certainly not impossible.

No, because the program may not be able to actually understand the syntax of your favorite programming language. As I mentioned in another comment, FRACTRAN is Turing-complete and you cannot just shove a string of Rust code at it because it has no idea what a string is; the best you can do is implement the "compiler" as working on some numerically-encoded version of Rust and producing some encoded version of a native binary on the other side. So you've lost the syntax because you've had to do that additional encoding.

Re: Forth implemented in Rust trait system

#36

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,…

I suspect a big reason is that you need an interpreter in addition to the compiler. From what I understand, the D gods spent quite some time and effort developing theirs.

For interpreted languages, there are no excuses; hooking into the interpreter at compile time is trivial. Full macros [0] are nice, but depends a lot on the syntax. A way to evaluate expressions at compile time [1] would go a long way.

[0] https://github.com/codr7/gfoo#macros

[1] https://github.com/codr7/gfoo#bindings

Re: Forth implemented in Rust trait system

#37

Earlier quoted context omitted.

Incorrect. Turing completeness means using the syntax of your favorite programming language is "merely" a matter of writing the appropriate program. What GP is proposing is completely impractical, of course. But not unreasonable, and certainly not impossible.

No, because the program may not be able to actually understand the syntax of your favorite programming language. As I mentioned in another comment, FRACTRAN is Turing-complete and you cannot just shove a string of Rust code at it because it has no idea what a string is; the best you can do is implement the "compiler" as working on some numerically-encoded version of Rust and producing some encoded version of a native…

You are misunderstanding the difference between “can in theory” and “presently able to do.”

Re: Forth implemented in Rust trait system

#38
post #36

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,…

I suspect a big reason is that you need an interpreter in addition to the compiler. From what I understand, the D gods spent quite some time and effort developing theirs. For interpreted languages, there are no excuses; hooking into the interpreter at compile time is trivial. Full macros [0] are nice, but depends a lot on the syntax. A way to evaluate expressions at compile time [1] would go a long way. [0] https://g…

If you do not want to implement a separate interpreter you can do multiple compilation passes instead.

Re: Forth implemented in Rust trait system

#39
post #17

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.

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 tha…

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.

Re: Forth implemented in Rust trait system

#40

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,…

Another issue not mentioned is cross-compiling.

If the result of my `sort ` function is dependent on `sizeof(void )` being 8, when I compile from my x86 hardware for a 32-bit only architecture, assumptions go awry.

Note that this isn't likely with something like sort, but definitely is* likely with precomputing values/structs etc.

Post reply on HN