Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Clojure for Lisp Programmers

Name: Anonymous 2011-08-07 8:51

http://blip.tv/clojure/clojure-for-lisp-programmers-part-1-1319721
http://blip.tv/clojure/clojure-for-lisp-programmers-part-2-1319826

It's a great talk. I've seen many people on /prog/ groundlessly criticizing Clojure, and it's sad. It this presentation Rich Hickey addresses all their points and provides a coherent rationale behind Clojure and its various ``unusual" design decisions. Despite being quite lengthy it doesn't get tedious as it quickly jumps from topic to topic, sometimes with interesting questions form the crowd between the jumps. You should definitely watch this video before forming your opinion about Clojure.

Name: Anonymous 2011-08-07 9:51

>>3
user=> (defn g [x] (first x))
#'user/g
;; This procedure is referentially transparent,
;; it can be optimized to (fn [x] 1).
user=> (defn f [x] (g '(1 2 3 4)))
#'user/f
user=> (f 'my-anus!)  
1
;; It really isn't referentially transparent,
;; because I can rebind `g' and change the meaning
;; of the procedure.
user=> (binding [g rest] (f 'my-anus!))
(2 3 4)
;; If the compiler erroneously did constant-folding,
;; it would have returned 1.
;; The core bindings are not safe either:
user=> (remove even? [1 2 3 4])
(1 3)
user=> (binding [filter (fn [& _] "no")] (remove even? [1 2 3 4])) ;; remove uses filter
"no"


This complicates inlining, constant folding, and other optimizations (see http://dis.4chan.org/read/prog/1309963234/7)
Other than breaking referential transparency, you can't be sure that your code will do what you mean: since it works outside your namespace, someone may rebind a procedure used inside your procedure, without even knowing it will break your code.
So, when using binding on (what probably are) procedure bindings, you either must know all the bindings used by that procedure, and the bindings used by the default (hoping that someone didn't rebound them already) procedure values used in that procedure, all the way up to the core, or hope that everything will be ok.

Clojure's quasiquote is an hack to preserve hygiene in the most retarded way:
user=> 'first
first
user=> `first
clojure.core/first

Clojure needs this hack, and namespaces, because it's not a Lisp-2 like CL, or else their macros would be utterly broken and unusable.
So, this works:
user=> (defmacro m1 [x] `(first ~x))
#'user/m1
user=> (m1 [1])
1
user=> (let [first rest] (m1 [1]))
1

This doesn't:
user=> (defmacro m2 [x] (list 'first x))
#'user/m2
user=> (m2 [1])
1
user=> (let [first rest] (m2 [1]))
()

This is a good enough solution, worse is better, why would you ever want software that works in the 100% of cases, etc.
But macros are not the point here, because both break using the magical binding:
user=> (binding [first rest] (m1 [1]))
()
user=> (binding [first rest] (m2 [1]))
()


So, dynamically scoped procedures:
- Make basic optimizations like inlining, reference inlining, constant folding, and more difficult.
- Make more advanced optimizations that rely on the value of a binding to not change hard/impossible.
- Break referential transparency.
- Break macros.
- Break procedures.
- Break lexical scope (duh).

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List