3 ms·
Thanks for these comments. I didn't realise alternative notations were planned and never took off. (Dylan in particular looks really interesting.) I can see th
by modernerd 8y ago
Thanks for these comments. I didn't realise alternative notations were planned and never took off. (Dylan in particular looks really interesting.)
I can see the value of homoiconicity / code as data from the perspective of someone writing a parser.
I've asked what writing code as s-expressions gets you as the end-user of a language before. People usually say, “macros” or “it's easier to manipulate code”. But macros exist in non-homoiconic languages, like Nim and Elixir. And in my short time using ClojureScript I'm not sure what manipulations Lisp syntax gave me that I don't already have with other languages in a modern text editor.
I'd love to see examples of accomplished Lisp users on YouTube or elsewhere, to see what those code manipulations look like.
- agumonkey 8y agodylan maintainer (bruce something) had lots of valuable insights about this I think I keep lisp syntax~ at heart because its nature made me learn and think recursively which is something of a rare value (and I'm not saying this as a cult, it really made me solve problems I couldn't in ways I was confident it would either work or be clear that my perspective was wrong, very very nice feeling). Another example is that I still prefer car/cdr even though they're laughably cryptic .. but they embody the whole culture (and have a tiny symmetry to it).
- straws 8y agoIt's true that macros exist in languages like Nim and Elixir, even C. They either use something more akin to string templates (expanding a macro fills in the holes) or a DSL for manipulating the AST (something new to learn to write code that writes code). One reason Lispers find macros so beautiful is the simplicity of writing macros using the exact same list processing functions. The code-is-data thing is reinforced through the fact that the AST is one-to-one with the syntax.
- lispm 8y ago> I didn't realise alternative notations were planned and never took off. See for example this program from McCarthy, 1960. On top is my Common Lisp translation and below you find the original code. The original had to be hand-translated into s-expression syntax to run it in Lisp - in 1960. https://gist.github.com/lispm/e44d81c3bb9b86d4313763647e058a59 https://gist.github.com/lispm/e44d81c3bb9b86d4313763647e058a... For a Lisp 2 (Lisp 2 as the successor to the original Lisp language - with the long promised notation) example see: http://www.softwarepreservation.org/projects/LISP/lisp2/SP-2450-SUMSQUARE_LCS.pdf http://www.softwarepreservation.org/projects/LISP/lisp2/SP-2... > But macros exist in non-homoiconic languages, like Nim and Elixir. Lots of languages have some kind of macros: C has textual transformations and Elixir has AST transformations. Lisp macros are different, since they are not AST transformations but token tree transformations. That means Lisp accepts arbitrary token trees (give that the first item is a macro identifier) and one can write programs to transform them. Languages which support macros for AST transformations, need to have the code parsed into an AST first. That means the expressions it can transform need to be already parsed into an AST - and the language accepted by the parser limits the expressions - unless one can add syntax changes to the parser, too. ASTs are special purpose data structures, while s-expressions are general purpose data structures and thus are not limited to expressing programs in a particular syntax and are not limited to express something which looks like a program. Lisp offers a bunch of macros: macros for transforming Lisp code, macros for transforming symbols, compiler macros for optimizing code, macros for transforming s-expressions, ... Additionally the macro has access to a full Lisp - which means it can do arbitrary computations: primitive transformations, complex language transpiling, full parsing&transformation, doing side-effects in the development environment, running at runtime in interpreters, ... That means for me as a programmer I can automate all kinds of code manipulation. There are many simple and many complex examples. Another advantage is that the language core can be reduced to a minimum set of syntactic forms and every other syntax can be built on top of it - and the developer uses the same mechanism as the language core: macros. This makes macros very pervasive - a programmer will use a lot of macros and may also program macros. One of the disadvantages is that macros also cost us: the code we see can be very different from the code which executes and there is an additional programming paradigm to understand: using syntactic abstractions with macros. One can learn some Lisp without touching macros (see for example SICP, which does not use macros), but in real world programs one might see a lot of macros. Paul Graham wrote a book, which explained use of macros in Lisp: On Lisp. Free download at: http://www.paulgraham.com/onlisp.html http://www.paulgraham.com/onlisp.html There are more disadvantages and also attempts to improve macros. See for example: http://library.readscheme.org/page3.html http://library.readscheme.org/page3.html An example for a typical use of macros is CLOS, the Common Lisp Object System. It has a three or four - layer architecture: layer 0 : meta object layer for CLOS - here CLOS is implemented in itself layer 1 : object layer for CLOS - here CLOS deals with simple representations of itself layer 2 : functional layer for CLOS - here have functions operating on CLOS objects layer 3 : macro layer for the CLOS programmer - here we have macros providing ways to configure CLOS programs Take for example defining a CLOS class: 0) on layer 0 CLOS has CLOS functionality to represent and create instances of classes and metaclasses, he were can also write extensions to new kinds of metaclasses 1) on layer 1 CLOS classes are objects: which have slots which are objects and which have superclasses which are objects 2) on layer 2 CLOS provides functions to create all that stuff: classes, slot objects, ... 3) on layer 3 CLOS provides the DEFCLASS macro which at macro expansion time - which typically will be triggered by compilation - can do all the transformations and can interface to the development environment at compilation time. The programmer will typically use layer 3 to define a class using the macro DEFCLASS. For more advanced use one could use the function ENSURE-CLASS Common Lisp originally in 1984 did not have any syntax for defining classes. The first CLOS implementation was a Lisp program which implemented all the layers above and provided the necessary syntax to define the new language objects: generic functions, methods, classes and some others. So it was mostly a user-level program which added a full complex object system - with only little code for implementation specific stuff. Thus the DEFCLASS macro could introduce any syntax it wanted as a user level program - since it is not constrained by a fronted parser. So the CLOS developers came up with something that was convenient for them to define classes. This could mean that it does something trivial by providing a different order to define things, make things shorter to write or that it does something more complex by actually checking the provided class configuration and doing some code transformations. The whole story of CLOS in CLOS itself is written in AMOP: https://en.wikipedia.org/wiki/The_Art_of_the_Metaobject_Protocol https://en.wikipedia.org/wiki/The_Art_of_the_Metaobject_Prot... See also the pointer there to the first and portable implementation of CLOS: PCL.
- modernerd 8y agoThank you so much for this thoughtful reply — I enjoyed the code samples and the details on Lisp's macro system, and I can see how its approach gives you more control to invent on top of the language. It's given me more to read and think about.
- noctuid 8y ago> I'd love to see examples of accomplished Lisp users on YouTube or elsewhere, to see what those code manipulations look like. For one example, see https://github.com/abo-abo/lispy/ https://github.com/abo-abo/lispy/ The author has a similar package for python, but it is not as powerful because of python's syntax. The author has demos of some of the functionality on his youtube channel: https://www.youtube.com/user/abo5abo/videos https://www.youtube.com/user/abo5abo/videos