2010-07-11 5 views
13

(Avertissement - Je suis conscient de l'importance de SEQS dans Clojure)lisp commun contre crée une liste à partir de deux symboles, clojure contre nécessite un seq à contre?

Dans Common Lisp la fonction contre peut être utilisé pour combiner deux symboles dans une liste:

(def s 'x) 
(def l 'y) 
(cons s l) 

Dans clojure - vous pouvez seulement contre sur une séquence - contre n'a pas été étendu pour travailler avec deux symboles. Donc, vous devez écrire:

(def s 'x) 
(def l 'y) 
(cons s '(l)) 

Y at-il un modèle de niveau supérieur dans Clojure qui explique cette différence entre Common Lisp et Clojure?

+0

J'ai programmé Clojure un peu et je n'étais même pas au courant! Si ce que vous prétendez est correct, c'est une bonne question :) –

+0

Notez qu'il est normalement préférable d'utiliser 'conj' que 'cons'. Pour plus de détails, voir ma réponse à cette question (et le commentaire de cgrand): http://stackoverflow.com/questions/3008411/clojure-seq-cons-vs-list-conj (En fait, cette réponse explique aussi la fonction de 'cons' dans Clojure par opposition au traditionnel Lisp' contre 'dans une certaine mesure.) –

+3

Votre premier exemple n'est pas une liste, c'est une paire. Une paire (a.b) est différente d'une liste de deux éléments (ab), qui se trouve être la paire (a. (b.nil)) – Zorf

Répondre

9

Dans Clojure, contrairement aux Lisps traditionnels, les listes ne sont pas les structures de données primaires. Les structures de données peuvent implémenter l'interface ISeq - qui est une autre vue de la structure de données qui lui est donnée - permettant aux mêmes fonctions d'accéder aux éléments de chacune. (Listes mettre en œuvre déjà. seq? vérifie si quelque chose met en œuvre ISeq. (seq? '(1 2)), (seq? [1 2])) Clojure agit simplement différemment (avec raison), en ce que lorsque cons est utilisé, une séquence (il est en fait de type clojure.lang.Cons) construit de a et (seq b) est retourné. (a étant arg 1 et 2 b arg) de toute évidence, les symboles ne sont pas et ne peuvent pas mettre en œuvre ISeq.

Clojure.org/sequences

Sequences screencast/talk by Rich Hickey Cependant, notez que rest a changé, et il est le comportement précédent est maintenant next, et que lazy-cons a été remplacé par lazy-seq et cons.

clojure.lang.RT

2

Quand vous dites

> (cons 'a 'b) 

en Common Lisp vous n'obtenir une liste, mais une paire en pointillés: (a . b), alors que le résultat de

> (cons 'a (cons 'b nil)) 

est la paire en pointillés (a . (b . nil)).

Dans la première liste le cdr() de ce n'est pas une liste, puisqu'il est ici b et non nil, ce qui en fait une liste incorrecte. Les listes appropriées doivent être terminées par nil. Par conséquent, les fonctions d'ordre supérieur comme mapcar() et les amis ne fonctionneront pas, mais nous économisons une contre-cellule. Je suppose que les concepteurs de Clojure ont supprimé cette fonctionnalité à cause de la confusion qu'elle pouvait causer.

+1

Il faut noter que '(a. (B.nil)) '_is_ une liste Lisp, communément appelée' (ab) '. – Svante

5

en Common Lisp CONS crée une cellule dite CONS, qui est similaire à un enregistrement avec deux emplacements: la « voiture » et le « cdr ».

Vous pouvez placer N'IMPORTE QUOI dans ces deux emplacements d'une cellule secondaire.

Les cellules Cons sont utilisées pour construire des listes. Mais on peut créer toutes sortes de structures de données avec des contre-cellules: arbres, graphiques, différents types de listes spécialisées, ...

Les implémentations de Lisp sont hautement optimisées pour fournir des cellules très efficaces.

3

Une liste Lisp est simplement un moyen courant d'utiliser des cellules de comparaison (voir Rainer's description). Clojure est mieux vu comme n'ayant pas de cellules de contre (bien que quelque chose de semblable puisse se cacher sous le capot). Le Clojure cons est un abus de langage, il devrait en fait être nommé prepend.

3

Dans Clojure, l'utilisation d'un vecteur à deux éléments est préférée: [:a :b]. Sous le capot de tels petits vecteurs sont implémentés sous forme de tableaux Java et sont extrêmement simples et rapides.

Une main courte pour (cons :a '(:b)) (ou (cons :a (cons :b nil))) est list: (list :a :b).