top | item 41535354

Lisp implemented in Rust macros

293 points| quasigloam | 1 year ago |github.com

79 comments

order

duetosymmetry|1 year ago

Greenspun's tenth rule strikes again! https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule

bigdict|1 year ago

nah, this is about codebases that are not themselves primarily lisp implementations

klrtaj|1 year ago

A great example of the rule is that C++ rediscovers car/cdr at a glacial pace in the template language. In C++26 one can finally get the car of a typename parameter pack with Args...[0].

I've no idea why they don't introduce car/cdr functions and nil for empty parameter packs and allow to store parameter packs instead of the current syntax insanity.

ForOldHack|1 year ago

HA!

"Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp."

HA HA!

dgfitz|1 year ago

What defines "sufficiently complicated" I wonder? Seems like a shit definition.

celeritascelery|1 year ago

I tried doing something similar to this once. I ran into an issue where I couldn’t define symbols with a dash in them (DEFINE MY-FN…). This is because rust will split the tokens on a dash. It was a small thing, but it meant I couldn’t just copy and paste snippets from a real lisp, I had to transform everything to underscore. Is it the same in your implementation?

quasigloam|1 year ago

Yes, at the moment I just assume that all atoms are rust idents because that makes it easier to implement (I can just match against $x:ident), so it doesn't support dashes in atoms. I guess you could match against `$x:ident $(- $y:ident)*` instead? That should work I think, I'd have to change some details in some of the arms but it seems like that would be possible.

zozbot234|1 year ago

> I ran into an issue where I couldn’t define symbols with a dash in them

I'm not seeing any issue? (DEFINE MYᜭFN...) works just fine.

gleenn|1 year ago

I wish there was a well-supported Lisp in Rust, not just the macros. I wonder how much memory safety you would retain or lose being based in Rust. Is it even possible to leverage the borrow checker any any sane way?

dokyun|1 year ago

Some Lisp compilers like SBCL are already capable of more extensive compile-time type-checking, but its information that the programmer is up to supply, and tends to be the part of the optimization stage rather than normal, incremental development. Lisp is usually defined by its dynamic nature, and run-time type checking is a big part of this. Making the programmer have to worry about how objects are managed before the fact would conflict with the freedom and expressibility one would expect from such a system. It also makes the compilers themselves simpler in comparison: Normal code without any extra declarations is safe by default, some systems might ignore such declarations for always being 'safe' (say if you're on a bytecode VM like CLISP or a Lisp machine that does hardware type-checking). SBCL compiles code quite quickly--so I've heard others tend to be even faster; the Rust compiler on the other hand is more likely to introduce a young programmer to the concept of thrashing. I really see them as two mutually incompatible worlds although they may not seem to be at first glance. One thing to remember is that Lisp is essentially the flagship "The Right Thing" language, while C is the "Worse is Better" language. Rust is neither, it is something entirely different which I think is overdue for a name, perhaps something that reflects the losing characteristics of both philosophies.

(This isn't to discredit the OP article: it's still a cool hack!)

p4bl0|1 year ago

That was fun. Thanks for sharing!

quasigloam|1 year ago

Thanks! It was fun to make. It was also instructive, as I learned that rust analyser doesn't handle macros generating millions of tokens :D

krick|1 year ago

Everyone is supposed to be cheering for how "fun" it is, but every time I see anything like that I cannot help but think, that I hate the fact it can be implemented in Rust. It never truly was a simple language, but I think it started as something way more manageable than what it has become.

zxexz|1 year ago

Rust is definitely not a simple language, I agree there.

I am quite likely a bit naïve here, but I'm having trouble understanding why you hate that this is possible. Now, the macro system definitely can generate near infinitely-complex code, but I'm not getting how implementing a sandboxed lisp using macros is a particularly potent example of the language being less manageable than at its genesis.

On another note, the fact that the type system is turing-complete, like with C++ templates or the Haskell type system (variously dependent on which GHC languages extensions you're using...), makes me want to see a lisp implemented that way!

pkolaczk|1 year ago

> but I think it started as something way more manageable than what it has become.

Hard disagree here. Rust team is continuously making the language easier to work with by removing limitations and making features more orthogonal. A notable example is non lexical lifetimes, impl Trait in return position or async traits. Also they have removed some features eg before it went 1.0, it even had GCed references built in with special syntax.

rapsey|1 year ago

The only real change since 1.0 was async. If you want to live without async that is completely up to you. It is an entirely optional part of the language.

If you want a language guided by the principle of simplicity Rust was never that and you have plenty of options elsewhere.

IshKebab|1 year ago

Nah, it really takes very little for something like this to become possible. I bet you could do it with C macros, which are supposedly simple.

(I checked; I win this bet: https://github.com/kchanqvq/CSP )

huijzer|1 year ago

Aren’t macro’s always very powerful but at the same time very tricky? I wouldn’t count the macro side into language complexity. It’s an add-on which you can but don’t have to use (I’m talking about creating macro’s here.)

josmar|1 year ago

If it's Turing Complete, there will be a LISP for it

brundolf|1 year ago

Wow and it uses macro_rules

meindnoch|1 year ago

But C++ is not a sane language because templates are Turing-complete, right?

danschuller|1 year ago

C++ is not a sane language for anyone with a passing familiarity. At least Rusts macros aren't literal text substitutions, a move towards the light.

keybored|1 year ago

There’s Turing Complete and Turing Tarpit.[1]

[1] Which one is the Rust macro system? I have no idea.

ramon156|1 year ago

C++ templates are a hell to develop with, at least macro_expand is a thing in Rust. It's the fact Rust's tooling is so well done.

elif|1 year ago

Hmmmmmmm.... Rustemacs?

Validark|1 year ago

This is super awesome!