Homoiconic Example In Many Programming Languages

Previous discussions of HomoiconicLanguages got bogged down in definitions. To cut this GordianKnot, let's define a concrete task that is easily implemented in a HomoiconicLanguage but impossible or difficult in other ProgrammingLanguages.

For starters, let's develop a spec from the LispLanguage example from HomoiconicLanguages.

Prohibited:


LispLanguage

Here's a demonstration of what homoiconicity looks like in Lisp (one or more semicolons designates a comment):

(setf b 3); setf means assign, so 3 is being assigned to b
b; b by itself asks the interpreter to print its value
  1. ; ...printed by interpreter; b's value is now 3

;;; assign to a a program fragment which assigns 15 to b: (setf a '(setf b 15))

;;; take a look at what a refers to now: a (SETF B 15); printed by interpreter

;;; evaluate the program fragment that a refers to: (eval a) ;;; ...the assignment of 15 to b has just happened: b; interpreter prints the value of b, 15

;;; Now traverse the data structure a refers to, finding the value 15: (car (cdr (cdr a))); car means left node of tree, cdr means right node
  1. ; printed by interpreter

;;; Now that we have verified where the 15 appears in the program fragment, change it: (setf (car (cdr (cdr a))) 37); modifies a's program fragment

;;; take a look at what a refers to now: a (SETF B 37); printed by interpreter

;;; evaluate the program fragment referred to by a (eval a) ; executes the program fragment displayed above (setf b 37) b; check the value of b
  1. ; ...printed by interpreter.
So we took a program fragment (an assignment) written in normal Lisp syntax, assigned it to a variable, and executed the contents of that variable. Indeed it performed the assignment. Then we modified the data structure representing the assignment, using the normal Lisp operators for operating on any kind of data, and evaluated the same variable again, and indeed the new assignment worked just fine.

So we see that data and code are completely interchangeable in Lisp, without extra muss or fuss. Lisp is homoiconic.

''I don't agree on this as a good example. See:

 >> b=3
 => 3
 >> b
 => 3
 >> a= "b=15"
 => "b=15"
 >> a
 => "b=15"
 >> eval a
 => 15
 >> b
 => 15
 >> a[-2..-1]
 => "15"
 >> a[-2..-1]="37"
 => "37"
 >> a
 => "b=37"
 >> eval a
 => 37
 >> b
 => 37
This is not an homoiconic language, yet the only difference you can find is that a string is treated more like an array than as a cons/list. I could have written #my_eval to take a cons cell s input and completely mimic the above lisp code, but there would be no advantage, the code just shows #eval not homoiconicity.''


ToolCommandLanguage

Here's the LispLanguage example translated into Tcl, in the form of an interactive session. Comments in Tcl are commands starting with #, so need a semicolon before them to start a new command. Lines entered into the interpreter are prefixed with a % prompt:

% set b 3;# Assign b the value 3
  1. ;# The value of b, echoed by the interpreter
% puts $b;# Print out the value of b.
% set a {set b 15}  ;# Assign to a the string "set b 15"
set b 15;# The code, echoed by the interpreter
% eval $a;# Run it using eval
% puts $b;# b is now 15
% set a [lreplace $a end end 37] ;# Replace the last item in a with 37
set b 37
% if 1 $a;# Run the new command by passing it as the third argument to if
% puts $b;# b is now 37
Note that, in Tcl, strings are the same as code. The string "set b 15" is a string, but also is a list of three items, and also is code which sets b to 15. You can't run $a by writing

% $a

since that would try to run a command called "set b 37", which presumably isn't defined, but you can pass it to the 'if' command as the run-if-true block of code.


JoyLanguage

As a pure FunctionalProgrammingLanguage, Joy doesn't have variables or assignment. Quotations are usually manipulated to pass on to other combinators. For the purposes of the example, we can posit Forth-like variables (b) and assignment (!) so that the example would be:

 define f == 7 b ! .(* a function *)
 f b @ .(* execute the function (7) *)

define a == [15 b !] . (* a quotation *) a i(* execute the quotation (i combinator) *) b @ . (* 15 *)

37 a rest cons (* modify the quotation: [37 b !] *) i(* execute the modified quotation *) b @ . (* 37 *)


IoLanguage

Following is an interactive session in IoLanguage:

Io> b:=3
==> 3
Io> a:=block(b=15)  #assign the code that updates b into 15 ( = is translated into updateSlot method call)
==> block(updateSlot("b", 15))
Io> a  #executes the block
==> 15
Io> b  
==> 15
Io> getSlot("a") code
==> block(updateSlot("b", 15))
Io> msg:=getSlot("a") message
==> Message_0x61b240 protos(Message_0x61b240)

Io> msg argAt(1) setName("37") ==> Message_0x61a240 protos(Message_0x61a240)

Io> msg code #see the code has changed ==> updateSlot("b", 37) Io> a ==> 37 Io> b #now b is 37 ==> 37


ArrLanguage

An interactive session in R:

> b <- 3
> b
[1] 3

> a <- quote(b <- 15) > a b <- 15 > as.list(a) #stripping the chrome [[1]] `<-`

[[2]] b

[[3]] [1] 15

> a[[3]] [1] 15 > a[[3]] <- 37 > a b <- 37 > eval(a) > b [1] 37


Contributors: DougMerritt, IanOsgood, JuneKim


Discussion:

Any ideas on making the spec less trivial? Ideas:

Any other prohibitions?

See also DefinitionOfHomoiconic and everything else with "Homoiconic" in the title for more rambling discussion.


See HomoiconicExampleInJava for some failed attempts and much discussion. (Java fails to evaluate source without writing to the file system.)


CategoryInManyProgrammingLanguages


EditText of this page (last edited August 28, 2012) or FindPage with title or text search