Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a compiled language be homoiconic?

People also ask

Can compiled languages be interpreted?

Thus every language can technically be compiled. And, since any compiled program can be written in the form "interpret the act of compiling the program, then interpret the result," every program can be interpreted as well.

What is the difference between an interpreter and a compiled language?

The difference between an interpreted and a compiled language lies in the result of the process of interpreting or compiling. An interpreter produces a result from a program, while a compiler produces a program written in assembly language.

Are compiled languages translated?

In a compiled language, the target machine directly translates the program. In an interpreted language, the source code is not directly translated by the target machine. Instead, a different program, aka the interpreter, reads and executes the code.

How are compiled languages executed?

The code of compiled language can be executed directly by the computer's CPU. A program written in an interpreted language is not compiled, it is interpreted. This language delivers better performance.


'Homoiconic' is kind of a vague construct. 'code is data' is a bit clearer.

Anyway, the first sentence on Wikipedia for Homoiconic is not that bad. It says that the language has to have a source representation using its data structures. If we forget 'strings' as source representation (that's trivial and not that helpful to have a useful concept 'homoiconic'), then Lisp has lists, symbols, numbers, strings etc. which are used to represent the source code. The interface of the EVAL function determines what kind of source representation the language is working on. In this case, Lisp, it is not strings. EVAL expects the usual variety of data structures and the evaluation rules of Lisp determine that a string evaluates to itself (and thus will not be interpreted as a program expression, but just string data). A number also evaluates to itself. A list (sin 3.0) is a list of a symbol and a number. The evaluation rules say that this list with a symbol denoting a function as the first object will be evaluated as a function application. There are a few evaluation rules like this for data, special operators, macro applications and function applications. That's it.

To make it clear: in Lisp the function EVAL is defined over Lisp data structures. It expects a data structure, evaluates it according to its evaluation rules and returns a result - again using its data structures.

This matches the definition of homoiconic: source code has a native representation using the data types of Lisp.

Now, the interesting part is this: it does not matter how EVAL is implemented. All that matters is that it accepts the source code using the Lisp data structures, that it executes the code and that it returns a result.

So it is perfectly legal that EVAL uses a compiler.

(EVAL code)  =  (run (compile-expression code))

That's how several Lisp system work, some don't even have an Interpreter.

So, 'Homoiconic' says that the SOURCE code has a data representation. It does NOT say that at runtime this source code has to be interpreted or that the execution is based on this source code.

If the code is compiled, neither the compiler nor an interpreter is needed at runtime. Those would only be needed if the program wants to eval or compile code at runtime - something that is often not needed.

Lisp also provides a primitive function READ, which translates an external representation (S-Expressions) of data into an internal representation of data (Lisp data). Thus it also can be used to translate an external representation of source code into an internal representation of source code. Lisp does not use a special parser for source code - since code is data, there is only READ.


yes. lisp can be compiled to a native binary


Seems to me to be an odd question:

Firstly, the homoiconic portion is the presented interface to the programmer. The point of languages is that they abstract a lower level functionality that preserves the same semantics as the higher level presentation (though a different means).

dsm's machine-code point is a good point, but providing:

  1. The syntax and semantics presented are homoiconic
  2. The translation to a lower level form (machine code or interpreted or otherwise) doesn't remove any of the original semantics then

why does the lower level implementation matter here?

Also:

compiled languages without a compile-time interpreter

Without some program interpreting it, it would be required to be native to the CPU, therefore the CPU's native language would be required to be homoiconic (or the VM running the code).

Languages without compile-time interpretation ... would be fairly constrained ... as they wouldn't be compiled at all.

But I am no expert, and maybe missing the point.


In the most literal form, C is homoiconic. You can get access to the representation of a function using &functionName and execute data using somePtrCastToFnPtr(SomeArgs). However this is at the machine code level and without some kind of library support you will find it very hard to work with. Some kind of embeddable compiler (I seem to remember that LLVM can do this) would make it more practical.


Lisp is normally compiled. There have been implementations with JIT compilers instead of interpreters.

Hence, it is not necessary to have an interpreter (in the sense of "not a compiler") for code-is-data languages.


Machine code itself is homoiconic, so yes.

Data or instructions are just a matter of semantics (and perhaps the segment of memory in which them lie).