I think “lisper” on the HN version of this article had a great summary:
“What’s really going on is that, in Lisp, code is a particular kind of data, specifically, it’s a tree rather than a string. Therefore, some (but not all) of the program’s structure is represented directly in the data structure in which it is represented, and that makes certain kinds of manipulations on code easier, and it makes other kinds of manipulations harder or even impossible. But (and this is the key point) the kinds of manipulations that are easier are the kind you actually want to do in general, and the kind that are harder or impossible are less useful. The reason for this is that the tree organizes the program into pieces that are (mostly) semantically meaningful, whereas representing the program as a string doesn’t. It’s the exact same phenomenon that makes it easier to manipulate HTML correctly using a DOM rather than with regular expressions.”
I don’t think tree vs string is the difference. For all languages, it is a string of bytes on disk and a tree once parsed in memory. Lisp just has a closer correspondence between tree and string, which makes it cognitively easier. I don’t know where somebody would draw the line that they are considered “homo”, equal.
I think at the point that the tree-literal syntax is the same as the language-proper syntax is a pretty good point to consider it equal. You can’t express arbitrary javascript programs in JSON, or any other C-family languages code in data-literal syntax. The lisp family however uses the same syntax for representing data as it does for representing its program.
Lisp just has a closer correspondence between tree and string, which makes it cognitively easier
Maybe not just cognitively but also in terms of programming. Many languages have complicated parsing and contexts where transformations aren’t as simple as an operation on a tree with regularity in its syntax and semantics.
The one’s Ive seen are definitely harder than LISP’s to work. Now, might be different if we’re talking a Scheme CPU, esp if microcoded or PALcoded. With SHard, it can even be built in Scheme. :)
REBOL did this better than most. All functions were just blocks, all functions were of fixed arity (with refinements to allow the arity to be changed), and had a rich syntax for literals of many different types…all of which means you could write powerful CL-style macros/reader macros with much richer syntax much more simply. Defining DSLs was dead simple.
I also liked how small the reblets were when I looked at REBOL and the IOS that came before iOS. If you love REBOL, what do you think of Red? If you tried it out, did you find anything better or worse?
Also, note that Red/System (see docs) supposedly lets one do system programming in REBOL/Red style. Figure you might like that concept given you like REBOL and apparently code in C language at work. Some could make it extract to C like PreScheme did and Ivory does to get benefits of HLL for low-level programs. Last I checked, it produces machine code directly using tooling implemented in REBOL.
I’ve looked at Red and it’s awesome, but I fear it makes a few of the same mistakes that REBOL did.
The main mistake is that the set of datatypes is closed and there’s a distinction between “types” like blocks and words, and objects that are user-defined.
Objects are not first-class types and types are not first-class objects. For example, at least the last time I looked, it was not possible to pass an arbitrary object to print and have it come out with your custom format.
The object system in REBOL was dying for a Common Lisp-style multiple dispatch object system. Then you could define a new print multimethod for objects of your class, for example.
So you have a closed datatype system and the best way to extend it, objects, aren’t integrated as well with the system as I’d hoped.
(The last time I wrote any REBOL code was probably almost ten years ago, though, so…Don’t hold me to any incorrect statements. :)
I don’t consider the datatype design a mistake, just a different choice. Objects are first class types, though they don’t (yet) have a literal lexical form. Construction syntax, as in Rebol, has been considered, but that feature hasn’t been needed yet, so it’s not locked down. And while we will learn from other languages, including CL, it doesn’t mean we can incorporate their every feature and still maintain a consistent design. We have someone who has built some really cool CL feature examples to experiment with*, but deep design changes need solid work done to show that they can integrate well with Red’s design and goals. They should be a step forward, not just in a different direction.
That said, if you want to play with new ideas, it’s easy. And we’ll see what features user defined types come with. If you want to influence that design, now is a great time to get involved.
name: object [
f-name: "John"
l-name: "Public"
formed: is [rejoin [f-name " " l-name]]
]
eqn: object [
n-1: 10
n-2: 2
fn: :add
formed: is [form fn n-1 n-2]
]
print+: func [val][
either object? :val [
print either in val 'formed [val/formed][mold val]
][print :val]
]
print+ name
print+ eqn
A lot of the “Unix way” stuff is kinda homoiconic, with the underlying data structure being lines of text in files. Sometimes, lines can be further divided by whitespace. There’s heaps of tools based around this, like ‘wc’, ‘awk’, ‘grep’ and ‘cpp’.
C is an odd case, because it with readline it is quite easy to write C code which manipulates C code in a very limited way. Thus the limitations of cpp’s macros. It seems like a shame that the most basic ‘file’ isn’t a more flexible data structure. But that’s a rant for another day :-)
I think “lisper” on the HN version of this article had a great summary:
“What’s really going on is that, in Lisp, code is a particular kind of data, specifically, it’s a tree rather than a string. Therefore, some (but not all) of the program’s structure is represented directly in the data structure in which it is represented, and that makes certain kinds of manipulations on code easier, and it makes other kinds of manipulations harder or even impossible. But (and this is the key point) the kinds of manipulations that are easier are the kind you actually want to do in general, and the kind that are harder or impossible are less useful. The reason for this is that the tree organizes the program into pieces that are (mostly) semantically meaningful, whereas representing the program as a string doesn’t. It’s the exact same phenomenon that makes it easier to manipulate HTML correctly using a DOM rather than with regular expressions.”
I don’t think tree vs string is the difference. For all languages, it is a string of bytes on disk and a tree once parsed in memory. Lisp just has a closer correspondence between tree and string, which makes it cognitively easier. I don’t know where somebody would draw the line that they are considered “homo”, equal.
I think at the point that the tree-literal syntax is the same as the language-proper syntax is a pretty good point to consider it equal. You can’t express arbitrary javascript programs in JSON, or any other C-family languages code in data-literal syntax. The lisp family however uses the same syntax for representing data as it does for representing its program.
[Comment removed by author]
Maybe not just cognitively but also in terms of programming. Many languages have complicated parsing and contexts where transformations aren’t as simple as an operation on a tree with regularity in its syntax and semantics.
Right. Von Neumann machine code is homoiconic, but I don’t think it exhibits many of the purported advantages of Lisp?
The one’s Ive seen are definitely harder than LISP’s to work. Now, might be different if we’re talking a Scheme CPU, esp if microcoded or PALcoded. With SHard, it can even be built in Scheme. :)
REBOL did this better than most. All functions were just blocks, all functions were of fixed arity (with refinements to allow the arity to be changed), and had a rich syntax for literals of many different types…all of which means you could write powerful CL-style macros/reader macros with much richer syntax much more simply. Defining DSLs was dead simple.
Ah, REBOL. You were too beautiful for this world.
I also liked how small the reblets were when I looked at REBOL and the IOS that came before iOS. If you love REBOL, what do you think of Red? If you tried it out, did you find anything better or worse?
Also, note that Red/System (see docs) supposedly lets one do system programming in REBOL/Red style. Figure you might like that concept given you like REBOL and apparently code in C language at work. Some could make it extract to C like PreScheme did and Ivory does to get benefits of HLL for low-level programs. Last I checked, it produces machine code directly using tooling implemented in REBOL.
I’ve looked at Red and it’s awesome, but I fear it makes a few of the same mistakes that REBOL did.
The main mistake is that the set of datatypes is closed and there’s a distinction between “types” like blocks and words, and objects that are user-defined.
Objects are not first-class types and types are not first-class objects. For example, at least the last time I looked, it was not possible to pass an arbitrary object to
print
and have it come out with your custom format.The object system in REBOL was dying for a Common Lisp-style multiple dispatch object system. Then you could define a new
print
multimethod for objects of your class, for example.So you have a closed datatype system and the best way to extend it, objects, aren’t integrated as well with the system as I’d hoped.
(The last time I wrote any REBOL code was probably almost ten years ago, though, so…Don’t hold me to any incorrect statements. :)
I don’t consider the datatype design a mistake, just a different choice. Objects are first class types, though they don’t (yet) have a literal lexical form. Construction syntax, as in Rebol, has been considered, but that feature hasn’t been needed yet, so it’s not locked down. And while we will learn from other languages, including CL, it doesn’t mean we can incorporate their every feature and still maintain a consistent design. We have someone who has built some really cool CL feature examples to experiment with*, but deep design changes need solid work done to show that they can integrate well with Red’s design and goals. They should be a step forward, not just in a different direction.
*examples
That said, if you want to play with new ideas, it’s easy. And we’ll see what features user defined types come with. If you want to influence that design, now is a great time to get involved.
A lot of the “Unix way” stuff is kinda homoiconic, with the underlying data structure being lines of text in files. Sometimes, lines can be further divided by whitespace. There’s heaps of tools based around this, like ‘wc’, ‘awk’, ‘grep’ and ‘cpp’.
C is an odd case, because it with
readline
it is quite easy to write C code which manipulates C code in a very limited way. Thus the limitations of cpp’s macros. It seems like a shame that the most basic ‘file’ isn’t a more flexible data structure. But that’s a rant for another day :-)