2011-10-06 8 views
5

Recientemente le pregunté acerca de las claves compuestas en mapas en clojure: How can you implement Composite keys in clojure? ...¿Cuál es el equivalente de clojure de anular "iguales" en java?

La respuesta fue que funcionan de manera similar a las teclas de Java - si algo anula "es igual a", entonces puede ser utilizado eficazmente como una clave.

Me preguntaba: ¿Hay macros que nos permitan anular "iguales" para estructuras de datos personalizadas? Por ejemplo, supongamos que quería usar un mapa como clave y definir la exclusividad como "si este mapa contiene dos o más elementos en común con otro mapa, son iguales". ¿Cómo podría anular el comportamiento predeterminado de un mapa?

En Java, considero que esta instalación es bastante poderosa cuando se hacen mapas de alta velocidad con miles de frijoles como claves.

Respuesta

4

No es que las colecciones clojure anule igual; Ignorar a los iguales ocurre en casi todos lados, estás haciendo algo interesante. Los tipos de Clojure proporcionan una implementación de iguales que debe ser consistente para todo el lenguaje (posiblemente de la misma manera que los equivalentes de Java estaban destinados a ser utilizados). Eso significa que las cosas que son "iguales" deben ser elementos singulares en conjuntos, y claves singulares en mapas, siempre, en todas partes. El diseño del lenguaje depende de eso. Clojure 1.3 realizó algunos cambios explícitos no compatibles con versiones anteriores para acercarse a ese ideal.

Ir contra el comportamiento esperado de iguales es muy probable que cause problemas en alguna parte, de alguna manera. Y no es demasiado difícil usar sus propios compuestos como conjuntos cuando realmente los necesita sin forzar su voluntad en el núcleo igual de todos modos.

Dicho esto, puede usar muchas funciones de interoperabilidad de Java y macros para pervertir el sistema de iguales si realmente lo desea. Ver http://clojure.org/datatypes como punto de partida.

1

Esto es una locura tanto en Clojure como en Java. No haga esto. Usted estaría rompiendo el contrato de la clase Object y la interfaz Map; todo tipo de cosas se desmoronarían por completo si usaran su clase de mapa personalizada. Si declara que dos objetos son equal, sus códigos hash deben ser idénticos, de lo contrario, el HashMap que los contiene no podrá hacer frente. Podrías hacer todo el hash a 0, por supuesto, pero ahí va tu mapa de alto rendimiento, ahora es una lista vinculada.

Dicho esto, puede hacer algo como esto en Clojure o Java utilizando un sorted-map (o SortedMap respectivamente) con un comparador personalizado. Sin embargo, hay trillones de trampas si elige un Comparador que no en realidad implemente la igualdad, sino que en su lugar una especie de "igualdad difusa".

+0

Reemplazar equivalentes está bien siempre y cuando anule también su función de hash.No es una locura en absoluto: un buen diseño estándar y común. Cualquier buen programa GUI/tipo de pelusa le recordará que anule uno si anula el otro. Usar el comparador es un patrón algo más desagradable, ya que exporta conocimiento de su clase a otro (el comparador) –

+2

Esto parece un poco de choque de paradigmas. Algunos piensan "objetos independientes, pregúntales si son iguales" mientras que otros piensan "composición de valores inmutables" donde la idea de los iguales es universal. –

+3

No estoy en contra de anular a todos, obviamente es necesario en Java. Anularlo * en la forma en que pregunta * es una idea terrible, porque es imposible escribir una función 'hashCode' que esté en línea con la decisión de hacer que' igual' devuelva verdadero para cualquier mapa que comparta al menos dos claves con este . – amalloy

5

Para agregar un poco de claridad a esta discusión, en Java es común anular hashCode y equals. Por ejemplo, intenta hacer un seguimiento de los empleados que tienen nombres, pero que también pueden tener un apodo. El objetivo es asegurarse de que esos empleados no estén duplicados. En ese caso, anularía equals y hashCode para ver solo la identificación del empleado. Cuando esos empleados se ingresan en una estructura de datos establecida, no se duplican. En Clojure, se podría hacer:

(deftype Employee [name id] 
    Object 
    (equals [a b] (= (.id a) (.id b))) 
    (hashCode [this] (.hashCode (.id this))) 
    (toString [this] (.name this))) 

(def vince (Employee. "Vince" 42)) 

(def vincent (Employee. "Vincent" 42)) 

(def tony (Employee. "Tony" 2)) 

(into #{} [vince vincent tony]) 

Pero es posible que desee buscar una solución "pura Clojure" estructura de datos en lugar de pasar el código hash, es igual, Java camino de interoperabilidad.

+0

¿Cómo sería una solución de estructura de datos "pura Clojure"? –

Cuestiones relacionadas