2010-07-11 13 views
13

(Disclaimer - Sono consapevole del significato di SEQS in Clojure)cons comuni lisp contro crea una lista da due simboli, contro i clojure richiede un seq a cons on?

in Lisp comune la funzione di contro può essere usato per combinare due simboli in un elenco:

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

In clojure - si può solo contro su una sequenza - i contro non sono stati estesi per funzionare con due simboli. Quindi si deve scrivere:

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

C'è un modello di livello superiore in Clojure che spiega questa differenza tra LISP comune e Clojure?

+0

Ho programmato un po 'in Clojure e non ero nemmeno a conoscenza di questo! Se ciò che affermi è corretto, questa è una buona domanda :) –

+0

Nota che normalmente è meglio usare 'conj' di' cons'. Per maggiori dettagli, vedere la mia risposta a questa domanda (e il commento di cgrand): http://stackoverflow.com/questions/3008411/clojure-seq-cons-vs-list-conj (infatti, questa risposta spiega anche funzione di 'cons' in Clojure in contrasto con il tradizionale' Lisp 'cons' in una certa misura.) –

+3

Il tuo primo esempio non è una lista, è una coppia. Una coppia (a.b) è diversa da una lista di due elementi (ab), che risulta essere la coppia (a. (B. Nil)) – Zorf

risposta

9

In Clojure, a differenza dei tradizionali Lisps, le liste non sono le strutture dati primarie. Le strutture dati possono implementare l'interfaccia ISeq - che è un'altra vista della struttura dati che viene fornita - consentendo alle stesse funzioni di accedere a elementi in ciascuna. (Elenchi già implementano questo. seq? verifica se qualcosa implementa ISeq. (seq? '(1 2)), (seq? [1 2])) Clojure semplicemente agisce diversamente (a ragione), dal fatto che quando cons viene utilizzato, una sequenza (in realtà è di tipo clojure.lang.Cons) costruito a e (seq b) viene restituito. (a essendo arg 1 e b arg 2) Ovviamente, simboli non e non possono implementare ISeq.

Clojure.org/sequences

Sequences screencast/talk by Rich Hickey Tuttavia, si noti che rest è cambiato, e il suo comportamento precedente è ora in next, e che lazy-cons è stato sostituito da lazy-seq e cons.

clojure.lang.RT

2

Quando si dice

> (cons 'a 'b) 

in Common Lisp non ottenete un elenco, ma un paio tratteggiata: (a . b), mentre il risultato di

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

è la coppia tratteggiata (a . (b . nil)).

Nel primo elenco il cdr() di quello non è un elenco, poiché è qui b e non nil, rendendolo un elenco non corretto. Gli elenchi appropriati devono essere chiusi da nil. Pertanto le funzioni di ordine superiore come mapcar() e gli amici non funzioneranno, ma salviamo una cella di controllo. Immagino che i progettisti di Clojure abbiano rimosso questa funzione a causa della confusione che potrebbe causare.

+1

Si noti che '(a. (B. Nil)) '_è_ una lista Lisp, comunemente nota come' (ab) '. – Svante

5

In Common Lisp CONS crea una cosiddetta cella CONS, che è simile a un record con due slot: la 'macchina' e il 'cdr'.

È possibile inserire QUALSIASI in questi due slot di una cella di controllo.

Le celle Contro sono utilizzate per creare elenchi. Ma si possono creare tutti i tipi di strutture dati con celle di controllo: alberi, grafici, vari tipi di elenchi specializzati, ...

Le implementazioni di Lisp sono altamente ottimizzate per fornire celle di controllo molto efficienti.

3

Un elenco Lisp è solo un modo comune di utilizzare le celle contro (vedere Rainer's description). Clojure è meglio visto come non avere contro le cellule (anche se qualcosa di simile potrebbe nascondersi sotto il cofano). Il Clojure cons è un termine improprio, in realtà dovrebbe essere chiamato solo prepend.

3

In Clojure è preferibile l'utilizzo di un vettore a due elementi: [:a :b]. Sotto il cofano questi piccoli vettori sono implementati come array Java e sono estremamente semplici e veloci.

Una mano corta per (cons :a '(:b)) (o (cons :a (cons :b nil))) è list: (list :a :b).

Problemi correlati