Fun with homoiconicity and equality semantics

So today I stumbled accross an interesting article on HN which goes into great detail about the limitation of equality in most languages. The author mentions:

I don’t know of any programming language which even attempts to do anything beyond reference equality for functions. But it’s easy to come up with examples where it would be useful! (An optimizer which removes duplicate code, e.g.) You’re on your own if you need this…

As it just so happened I’d written about this the week before!

https://andersmurphy.com/2020/03/01/clojure-code-as-data.html

Clojure is homoiconic (code is data) and it has great equality semantics which makes it relatively trivial to write these kind of tools.

This example could be expanded with some heuristics to use semantic equality rather than syntactic equality. Even to automatically refactor the code. Or as a macro to automatically optimize code at compile time. :exploding_head:

That being said I’m not sure how useful this is as code duplication hasn’t been common in my experience with Clojure. Still pretty fun so I thought I’d share. :slight_smile:

2 Likes

Another example it’s easy to come up with is in ClojureScript “Reagent” programs. Your function is supposed to return a whole page’s Hiccup HTML, and the framework should briskly spot the differences relative to last time, and re-draw only what needs re-drawing. So your function returns

[:html [:body [:p "Hello" [:a ...

and all is well, quite stable. Then you add just a little bit

[:html [:body [:p "Hello" [:a {:on-click #(...

and from that time onward, the A element is “different” every time your function runs. (To restore order, you lift the function out and refer to it by a stable symbol.)

1 Like

@andersmurphy fun article!

At last year’s Strange Loop, Paul Chiusano gave a really fascinating talk about his distributed programming language Unison. It takes a really fascinating approach to function equality: functions are stored as a hash of their contents (with bound variable names normalized so that (fn [x] (inc x)) and (fn [y] (inc y)) hash to the same value). Names are just convenient aliases for those functions. Among other things, this eliminates dependency and versioning issues, makes incremental builds and testing trivial, and supports elastic highly distributed systems. Really worth checking out!

That was a really nice talk, indeed! Thanks for sharing!
(though, if I may channel Rich for a moment, he only talked about benefits, and didn’t mention any trade-offs… It’ll be interesting to follow, in any case)

Possible related: https://youtu.be/gE6SsLAZ4Mo?t=462

Possible trade-off: "… most proposals that I have seen require a hash table lookup for each function call and that would slow down the function call so much that the entire system would be unusable … "