Live data from Hacker News

Debugging compilers in Clojure

jpmonettas.github.io

11–14 of 14 posts

Re: Debugging compilers in Clojure

#11
post #10

Earlier quoted context omitted.

Scheme might be different here, I'd have to read the standard, but it's true of Common Lisp at least. You have to distinguish here, I think, between what's valid input to eval and the evaluation rules for given inputs. Anyways, here's CL's spec for eval[1]: eval form => result* Form is defined in the glossary as "form n. 1. any object meant to be evaluated. 2. a symbol, a compound form, or a self-evaluating object."[…

> Scheme might be different here [...] Yep, I meant to specify that a subset of your original claim is true for all Lisps, not that your claim was not true for certain ones like CL. > IMO, the useful definition of homoiconicity is "the domain and codomain of eval are the same type". I do not think that is a useful definition. Under that definition, any language can be made homoiconic by providing a library with an ev…

“The most useful definition of homoiconic IMO is that the internal representation of the language (the AST) is the same as the external representation of the language”

Except this is never true, unless your AST is a string. And Racket’s internal representation (syntax objects) is much more complicated than what is apparent from the text. So, in my opinion, defining homoiconicity in terms of the textual syntax is basically impossible. (And I’m sympathetic to Shriram Krishnamurthi’s claim that homoiconicity doesn’t mean anything).

The interesting property, in my opinion, is that languages like Common Lisp are not specified in terms of the textual syntax and so the textual representation is irrelevant to the semantics of the program: a visual tool that produces lisp forms is as valid a “syntax” of Common Lisp as the standardized textual representation produced by READ.

Re: Debugging compilers in Clojure

#12
post #10

Earlier quoted context omitted.

> Scheme might be different here [...] Yep, I meant to specify that a subset of your original claim is true for all Lisps, not that your claim was not true for certain ones like CL. > IMO, the useful definition of homoiconicity is "the domain and codomain of eval are the same type". I do not think that is a useful definition. Under that definition, any language can be made homoiconic by providing a library with an ev…

“The most useful definition of homoiconic IMO is that the internal representation of the language (the AST) is the same as the external representation of the language” Except this is never true, unless your AST is a string. And Racket’s internal representation (syntax objects) is much more complicated than what is apparent from the text. So, in my opinion, defining homoiconicity in terms of the textual syntax is basi…

> textual representation is irrelevant to the semantics of the program

It's not completely irrelevant, since Common Lisp has the idea of a text-based file with source code and a compilation mode for it (-> COMPILE-FILE).

But generally what you say is true. We see that especially in two places: 1) the Lisp interpreter, which runs non-text s-expressions and 2) special development environments, like Interlisp-D/Medley where a prominent way to edit Lisp code is a structure editor, which manipulates s-expressions in memory.

Re: Debugging compilers in Clojure

#13

This is a nitpick, but I think this is a bad mental model of most lisps: > Since the compilation unit of most Lisps is a form instead of a file like on most other languages, the core of the ClojureScript compiler can be seen as a program that will take a string representing a Clojure form as input, read it, recursively parse it into a tree of expressions also known as an AST (abstract syntax tree), and then walks dow…

Mainly, what is wrong with the statement is that such a program/function which reads forms from a file and compiles them is window dressing around a compiler, not its core.

Re: Debugging compilers in Clojure

#14
post #10

Earlier quoted context omitted.

Scheme might be different here, I'd have to read the standard, but it's true of Common Lisp at least. You have to distinguish here, I think, between what's valid input to eval and the evaluation rules for given inputs. Anyways, here's CL's spec for eval[1]: eval form => result* Form is defined in the glossary as "form n. 1. any object meant to be evaluated. 2. a symbol, a compound form, or a self-evaluating object."[…

> Scheme might be different here [...] Yep, I meant to specify that a subset of your original claim is true for all Lisps, not that your claim was not true for certain ones like CL. > IMO, the useful definition of homoiconicity is "the domain and codomain of eval are the same type". I do not think that is a useful definition. Under that definition, any language can be made homoiconic by providing a library with an ev…

"Homoiconic" means that code definitions are stored in the original textual form, or possibly in a tokenized form from which the text is easily recovered. Thus the program's definitions may be edited, without referring to external source code.

Bash is homoiconic because you can type "set" with no arguments, and see all the function definitions in their original syntax (albeit reformatted and without comments). You can copy and paste these definitions, editing them in between.

In Common Lisp, the perhaps little-known ed function supports homoiconicity. Function definitions whose original definitions is available may be edited. (Like Bash's set, ed will serve you up a reformatted function without comments.)

Homoiconicity is mostly stupid and irrelevant, and an earmark of immature, naively implemented languages. A Lisp which compiles every definition that is fed into it, throwing away the original nested lists, cannot support a function like ed, and fails to be homoiconic, yet has all the oft discussed advantages of Lisp.

A feature that is close to homoiconicity that is useful is a REPL with history recall. In a REPL with history recall, we can write definitions. Even if those definitions are compiled, so the language image has no record of the code, the REPL has the original text in memory. So by history recall, we satisfy the use case of the programmer who wants to recall a definition, edit it and replace it. Or some of those use cases. Obviously, a program doesn't come with a REPL history of its definitions; only one that we made in the REPL.

Post reply on HN