Macro macro macro! :grinning: <https://youtu.be/2J...
# two-minute-week
d
Macro macro macro! 😀

https://youtu.be/2JM7RAj8Nc4

(Please do pause the video as necessary to figure out what is happening in that first demo.)
👍 1
Also I translated this and my previous video to Spanish [como subtítulos] porque podía:

https://www.youtube.com/watch?v=Eqm2Eip884E

👍 1
c
Do you have a link for background to the project? It's kind of hard to follow without context 😅
d
Sure! For the first video: http://ecsharp.net/lemp For the second (older vid): http://loyc.net/loyc-trees The LeMP tool in the first video is built upon the tools in the second.
👍 1
It's hard to give enough information in two minutes, so let me know if you have questions.
I wrote a little thing, in case it helps anyone understand the video: http://loyc.net/loyc-trees/#loyc-trees-in-action
r
This project has a vibe similar to the original design and implementation of C++. A preprocessor on top of C. In this case, a preprocessor on top of C#. It's always interesting to me to see the struggles that come about when building macros in an Algol based language. Nim macros deal with many of the same issues. There always ends up being a lot of boilerplate and ceremony around dealing with the tree structure. (That you inevitably hide by writing more macros once you are bootstrapped far enough lol).
d
What issues do you mean? What boilerplate and ceremony? I don't think LeMP is similar to C++, as it solves problems that C++ never tried to solve (whereas most problems solved by C++98 were solved by C# 2.0... and those problems solved by C++ but not C# are largely not solved by LeMP either. Even C++'s new support for compile-time code execution has little resemblance to what LeMP does, as LeMP simply has a macro to invoke the C# interactive engine at compile-time.)
r
Let me clarify. I am speaking from a historical perspective. I don't mean that it solves similar problems, I mean that it is similar to the original implementation of C++. In 1979 Bjarne Stroustrup created C++ as a preprocessor on top of C. It didn't start out as a separate language from whole cloth. LeMP seems similar in that regards. In regards to boilerplate, your first example:
change_temporarily
is in fact built up of several lower level macros is it not? And this required you to implement several other fairly complicated bits of infrastructure, including
collection_with_change_events
(if that's not boilerplate / ceremony code, idk what is) and your
macro macro
to interface with the C# interactive engine. You don't deal with the C# interactive engine directly in your
change_temporarily
macro (though you could in theory), instead you have built up to it using a series of lower level macros that you progressively develop. I don't mean to imply this is a bad thing! I believe what you are doing is fundamental to the nature of macro systems. You inevitably build up infrastructure organically on top of itself like this. What is interesting to me is the shape macros take in an imperative Algol descendent language compared to a lisp ends up being very different (more verbose). As the resident shill for the fringe language Nim in this community, which has a very similar macro system (at least on the surface), I can tell you that Nim has run into many of the same issues you are running into. This appears to be an interesting case of convergent evolution.
d
change_temporarily
is built on the
on_finally
macro, that's true, but I don't see how this is any different from Lisp where macros are even more ubiquitous. Can you give an example of something that would end up more verbose in LeMP (or Nim, though I haven't used Nim nor Lisp) than in Lisp?
CollectionWithChangeEvents
isn't used by anything at all (I wrote it and then decided I didn't need it after all).
macro
is, of course, a macro, but in a Lisp I understand that one typically also uses a macro to define other macros. I don't think this is fundamentally a matter of Algol (conventional) languages vs Lisps. The "Loyc tree" way of seeing things is intended to abolish most of the differences between "Lisps" and "Algols", so that the only differences left are the parser, printer and some historical baggage that neither type of language is able to shed. And by the way, something that might not be obvious is that I'm trying to shift C# from being a "statement-based" language to a "expression-based" language like Lisp is. So Enhanced C# is fundamentally expression-based, e.g. the statement
if (c) Foo();
is perfectly equivalent to the expression
#if(c, Foo())
. Admittedly there can be some "ceremony" necessary to bridge this gap, e.g. the
case
statement expects an expression argument, so if the user wants to write a statement in its natural form
if (c) Foo();
, the user must enclose the statement in braces, and the
case
statement must in turn remove the braces before processing the syntax tree. I would say this falls into the category of historical baggage - there is no reason an Algol-style language can't embrace an expression-based nature from the start, like LES does. In addition, since LeMP is a preprocessor it does face substantial difficulties as a result of the fact that it can't add features to C# itself.
So, yeah, I have to write quite a bit of infrastructure to get macros to work well on an uncooperative language like C#, but I don't consider this to be a result of C# being in the Algol family per se, rather it is the result of various decisions they made, such as having a bright red line between expressions, statements, and declarations (a decision which they doubled down on when they introduced the new pattern syntax, creating another category of syntax that is distinct from, and highly ambiguous with, the others... sigh)
Hmm, but now that I think about it, I can't name a single Algol-style language, other than my own LES, that rejected the statement/expression dichotomy. LES is also meant to provide homoiconicity. I'd be kind of shocked if it turned out that I was the first one to do this stuff in an Algol style language... but I'm inclined to apologize, because from your perspective you're probably seeing Algol languages as they are (or tend to be), which is perfectly reasonable, and I'm seeing them in an unconventional way, and so the onus is on me to explain that....
r
I think you hit the nail on the head: Algol languages have pretty much all kept the statement/expression dichotomy. Adding macros to an Algol language seems to drive the language to push more things into expressions. Nim is interesting because it cares less about homoiconicity as a principle. It's a practical language first and foremost. But it's interesting to see certain homoiconic properties emerge (and also where they fail) Nim trying to get more "expression-ey" and failing https://github.com/nim-lang/Nim/pull/11992 Nim having similar issues with
case
😛 https://github.com/nim-lang/Nim/issues/12874
👍 1
d
now that I think about it, I can't name a single Algol-style language, other than my own LES, that rejected the statement/expression dichotomy
Algol 68 is an expression-oriented language. It doesn't have macros, though. The family of functional languages including ML and Haskell are strongly influenced by Algol, and are also expression oriented. Maybe you meant C-style language?
d
Based on what Wikipedia says about Algol 68, it sounds like a pretty standard language in terms of the statement-expression dichotomy: https://en.wikipedia.org/wiki/ALGOL_68#Expressions_and_compound_statements Haskell syntax is based mainly on the Lambda calculus of the 1930s. Still, ML and Haskell could have been influenced by Algol.