haskell lens

¿Cuál es la diferencia entre `ix` y` at` en la biblioteca de Lens de Haskell?



(1)

Que at y ix son diferentes ya es notable si observa las instancias disponibles para las clases que contienen estas funciones:

  • instancias de At : Map, IntMap, HashMap
  • instancias de Ixed : [a], Map, ByteString, Text y mucho más

Todas las instancias si At son también una instancia de Ix , pero no todas las instancias de Ix son también una instancia de At .

Entonces, ¿cuál es la diferencia entre ellos? At es para contenedores que permiten insertar claves que no están presentes en el contenedor. Esto es obviamente posible para un Mapa, pero no para una lista. Para poder seguir indexando en una lista y cambiar los elementos que están allí, Ix no permite crear nuevos elementos, sino que simplemente "no hace nada" cuando intenta escribir en una clave que no está allí.

>>> Data.Map.fromList [(''a'', 1)] & at ''b'' .~ Just 4 fromList [(''a'',1),(''b'',4)] -- Inserts value >>> Data.Map.fromList [(''a'', 1)] & ix ''b'' .~ 4 fromList [(''a'',1)] -- Does nothing because key is not present

(También hay un atajo para a .~ Just b , a ?~ b )

Técnicamente, esta diferencia proviene del hecho de que ix es un Traversal mientras que at es un Lens . Y como at es un Lens que "devuelve" un Maybe Something, no se puede componer con una lente que solo tome un "Something". ix es un Traversal con valores de 0 o 1, por lo que puede componer ix como cualquier otro recorrido (al igual que puede escribir traverse . traverse . (^?) solo toma el primer valor (cabeza) de ese recorrido.

Siempre puedes derivar ix desde:

ixAt = at . traverse

La misma definición ya está en la lente , excepto que usa (<.) Para la composición para mantener el índice desde. ( at y ix son ambas lentes indexadas / transversales).

Fuera del tema : la mayoría de los operadores de lentes también tienen nombres de infijo, puede encontrar una tabla (incompleta) en: https://github.com/ekmett/lens/wiki/Operators

Todo lo que sé es que uno funciona y el otro no.

Contexto: Tengo una estructura de datos F que contiene un Data.Map.Map k S a otra estructura de datos S Mi objetivo era construir una Lens que, dada una F y k , describiera un campo en S

La dificultad es que la clave k puede no estar presente en el mapa. Eso está bien, la función puede envolver su retorno en Tal vez. Sin embargo, no pude propagar una lente a través de Maybe at . Después de leer un montón de respuestas de desbordamiento de pila, encontré esta .

Resulta que reemplazar con ix resolvió mis problemas de tipo si también reemplazaba (^.) Con (^?) .

Pregunta: Parece que at y ix hacen lo mismo, al menos con respecto a Map . Ambos toman una clave y le dan un ''Lens'' al valor de esa clave. Sin embargo, ix parece jugar bien con el operador de composición de funciones (.) . ¿Cuál es la diferencia entre los dos?

Fuera de tema Rant:

Me gustan los operadores de infijo tanto como el siguiente tipo, pero el paquete Control.Lens parece haberse ido un poco por la borda. Para un usuario nuevo que tenga algunos nombres en inglés y una clave en algún lugar, disminuiría la curva de aprendizaje. Debido a la gran cantidad de clases de envoltorios utilizadas en la biblioteca de Lens, es particularmente difícil revisar las firmas de tipo si aún no sabe lo que está pasando. Mi código está empezando a parecerse a Perl, por el amor de Dios.