4 ms·
Strictly speaking: yes. But whether conses (aka pairs), lists, or other derivative structures support pervasive FP in a language is probably most influenced by
by wooby 8y ago
Strictly speaking: yes. But whether conses (aka pairs), lists, or other derivative structures support pervasive FP in a language is probably most influenced by whether conses are mutable or not.
In Common Lisp, they are. In Scheme, they are not.
Mutable conses are useful because at least because values can be accumulated in a list from the end by retaining and mutating the tail.
However, the presence of mutable conses detracts from a language's ability to support FP, since it must be done by convention and with much copying.
I see Clojure's innovation in this area not in the fact that its lists are immutable (Scheme did this already) but in the fact that its lists are immutable and there's never a need to mutate the tail, because lazy sequences are supported throughout the language. The icing on the top of the story is that concrete lists and lazy sequences both inhabit the "Seq abstraction", and so don't require different APIs most of the time.
Of course, I'm pretty sure lazy sequences existed before CL was standardized (they're in SICP), but I can imagine how the designers would have preferred a simple, well-known tool (mutable conses) over admitting a whole other sequence abstraction. Plus, immutable conses would have been a breaking change.
So, it's not that anything that Clojure does with regard to lists couldn't have been done before, just that it wasn't -- while also being packaged in a vehicle that was wildly compelling for many other unrelated reasons.
- lispm 8y ago> because lazy sequences are supported throughout the language. Most of the time Lisp implements these data structures themselves - many/most Lisps are largely implemented in itself. As such Lisp exposes and provides very low-level data structures like conses, which are simply two element cells. Basically Lisp here is on the level of assembler - which is reflected that the historical name CAR means something like 'contents of the address register'. Clojure's persistent immutable sequences are a very different data structure. Clojure does not expose its implementation and the implementation does not easily map to hardware, especially since quite a bit of the language is implemented in terms of the JVM and the Java language. Example: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentList.java https://github.com/clojure/clojure/blob/master/src/jvm/cloju...
- fiddlerwoaroof 8y agoScheme's conses are mutable: r7rs (and the previous standards) define set-car! and set-cdr! to mutate the parts of the conses. One of the reasons why Racket is not a Scheme is that Racket's conses are immutable.
- wooby 8y agoThanks for clarifying. I remembered it as a point of contention in the Scheme community.
- kazinator 8y ago"lazy" and "immutable" are orthogonal. "lazy" happily co-exists with "mutable". TXR Lisp has mutable lazy conses: 1> (take 12 (range 1)) (1 2 3 4 5 6 7 8 9 10 11 12) 2> (let ((r (range 1))) (inc [r 4] 15) (take 12 r)) (1 2 3 4 20 6 7 8 9 10 11 12) There is no reason to prevent mutation; all we have to do is assume that programmers are grownups and treat them as such. Remember, mutate responsibly; if you mutate, don't derive. Even if someone has been mutating "harmless" local variables, do not jump into the same lexical scope with them.