2011-05-18 6 views
13

De a comment on another question, alguien dice que la expresión de Clojure prefiere devolver nil en lugar de una lista vacía como en Scheme. ¿Porqué es eso?¿Por qué Clojure prefiere preferir devolver nil en lugar de lista vacía como Scheme?

igual,

(when (seq lat) ...) 

en lugar de

(if (empty? lat) 
    '() ...) 
+2

Supongo que [este hilo] (http://stackoverflow.com/questions/5830571/why-did-father-of-clojure-say-that-schemes-true-false-are-broken) debería ser de ayuda clasificando esto – skuro

+0

Un valor falso es ciertamente más útil para devolver que uno verdadero. Otros ceceos (como Common Lisp) tratan la lista vacía como falsy. Clojure no sigue el ejemplo, como se describe en las respuestas en el enlace de skuro. Me sorprendería si '(si (SEC alguna lista) ...' _siempre_ ejecutado la primera forma. –

+0

Esquema frecuencia no devuelve una lista vacía, a menudo procedimientos de Scheme volverán '# F' o ningún valor todos. la lista vacía se devuelve en su mayoría como el caso base de procedimientos recursivos. – amoe

Respuesta

23

puedo pensar en algunas razones:

  • distinción lógica. En Clojure nil significa nada/ausencia de valor. Mientras que '() "la lista vacía es un valor -. Que sólo pasa a ser un valor que es una lista vacía Es muy a menudo conceptual y lógicamente útil distinguir entre el Fit dos

  • con JVM. - el modelo de objetos JVM admite referencias nulas. Y una gran cantidad de API Java devuelven nulo para significar "nada" o "valor no encontrado". Por lo tanto, para asegurar la interoperabilidad JVM, tiene sentido que Clojure use nil de una manera similar.

  • pereza - la lógica aquí es bastante complicado, pero mi entendimiento es que el uso de cero en el caso de "no lista" funciona mejor con Clojure de lazy sequences. Como Clojure es un lenguaje de programación funcional y vago por defecto, tiene sentido que este uso sea estándar. Ver http://clojure.org/lazy para una explicación adicional.

  • "Falsiness" - Es conveniente utilizar nula en el sentido de "nada" y también significa "falso" al escribir código condicional que examina colecciones - para que pueda escribir código como (if (some-map :some-key) ....) para probar si un HashMap contiene una valor para una clave dada.

  • Rendimiento - Es más eficiente para la prueba de cero a examinar una lista para ver si se vacía ... por lo tanto, la adopción de este idioma como estándar puede conducir a un mayor rendimiento del código idiomático

Nota que todavía hay algunas funciones en Clojure que devuelven una lista vacía. Un ejemplo es el reposo:

(rest [1]) 
=>() 

Este question on rest vs. next entra en algunos detalles de por qué esto es .....

+1

Fwiw, si regresa '()' como un literal, el llamante puede probar rápidamente, debido a su clase será 'clojure.lang.PersistentList $ EmptyList'. La comprobación de eso es seguramente más rápida que probar' empty? 'o' seq', aunque probablemente aún sea un poco más lento que comprobar 'nil'. – amalloy

1

Desde que escribí el comentario voy a escribir una respuesta. (La respuesta de skuro proporciona toda la información, pero tal vez demasiada)

  1. Primero de todo, creo que las cosas más importantes deben estar en primer lugar.
  2. seq es precisamente lo que todo el mundo usa la mayor parte del tiempo, pero está bien empty? a su justo (not (seq lat))
  3. En Clojure '() es verdadera, por lo normaly que desea devolver algo eso es falso si se termina la secuencia.
  4. si solo tiene una rama en su propiedad y si la otra devuelve false/'() o algo por el estilo, ¿por qué debería escribir esa rama? when tiene una sola rama, esto es especialmente bueno si quieres tener efectos secundarios. No es necesario que use do.

Vea este ejemplo:

(si es falso '() (do (println 1) (println 2) (println 3)))

puede escribir

(cuando es verdadero (println 1) (println 2) (println 3))

No es tan diferente, pero creo que es mejor leer.


P.S.

No es que no son funciones llamadas if-not y when-not que son a menudo mejor que (if (not true) ...)

+0

gracias por la clarifcation en su anterior comentario –

6

También tenga en cuenta que la unión de tipos de colección y nula forman un monoide, con la concatenación monoide plus y nada el monoide cero. Así que nil mantiene la semántica de la lista vacía bajo concatenación mientras que también representa un valor falso o "perdido".

Python es otro lenguaje donde las identidades monoides comunes representan falsos valores: 0, lista vacía, tupla vacía.

+0

¿qué dijiste? –

+5

¿Sabes cómo si tienes suma, alguna n + 0 = n? Y si tienes el lógico o, any n o true = n? Y si tiene la concatenación de listas en Clojure, any (concat n nil) = n? Entonces, existe este patrón de "cosas faltantes" en las operaciones. Clojure usa nil para representar la idea de "faltante" en varios casos, por lo que puede hacer que los algoritmos comunes (por ejemplo, walkers de árbol) sean más generales y claros. –

4

De The Joy of Clojure

Debido colecciones vacíos actúan como true en contextos de Boole, se necesita un lenguaje para probar si hay algo en una colección de procesar. Afortunadamente, Clojure proporciona una técnica de este tipo:

(seq [1 2 3]) 
;=> (1 2 3) 

(seq []) 
;=> nil 

En otra Lisps, como Common Lisp, la lista vacía se utiliza para significar nil. Esto se conoce como nil punning y solo es viable cuando la lista vacía es falsey. Volviendo a nil, aquí está la manera en que clojure reintroduce nil punning.

Cuestiones relacionadas