Hay al menos tres bibliotecas populares para acceder y manipular campos de registros. Los que conozco son: acceso de datos, etiquetas y lentes.
Personalmente comencé con el acceso a datos y los estoy usando ahora. Sin embargo, recientemente en Haskell-Cafe había una opinión de que las etiquetas eran superiores.
Por lo tanto, estoy interesado en la comparación de esas tres (y tal vez más) bibliotecas.
data-structures
haskell
record
lenses
Tener
fuente
fuente
lens
paquete tiene la funcionalidad y la documentación más ricas, por lo que si no le importa su complejidad y dependencias, es el camino a seguir.Respuestas:
Hay al menos 4 bibliotecas que sé que proporcionan lentes.
La noción de una lente es que proporciona algo isomorfo a
proporcionando dos funciones: un captador y un definidor
sujeto a tres leyes:
Primero, que si pones algo, puedes recuperarlo
Segundo, obtener y luego configurar no cambia la respuesta
Y tercero, poner dos veces es lo mismo que poner una vez, o más bien, que gana el segundo puesto.
Tenga en cuenta que el sistema de tipos no es suficiente para verificar estas leyes por usted, por lo que debe asegurarse usted mismo sin importar la implementación de lentes que use.
Muchas de estas bibliotecas también proporcionan un montón de combinadores adicionales en la parte superior y, por lo general, alguna forma de maquinaria de plantilla haskell para generar automáticamente lentes para los campos de tipos de registros simples.
Con eso en mente, podemos recurrir a las diferentes implementaciones:
Implementaciones
fclabels
fclabels es quizás el más fácil de razonar sobre las bibliotecas de lentes, ya que
a :-> b
se puede traducir directamente al tipo anterior. Proporciona una instancia de Categoría para la(:->)
cual es útil ya que le permite componer lentes. También proporciona unPoint
tipo sin ley que generaliza la noción de una lente utilizada aquí, y algunas tuberías para tratar los isomorfismos.Un obstáculo para la adopción
fclabels
es que el paquete principal incluye la plomería template-haskell, por lo que el paquete no es Haskell 98, y también requiere laTypeOperators
extensión (bastante no controvertida) .acceso a datos
[Editar:
data-accessor
ya no usa esta representación, pero se ha movido a una forma similar a la dedata-lens
. Sin embargo, mantengo este comentario.]el acceso a datos es algo más popular que
fclabels
, en parte porque es Haskell 98. Sin embargo, su elección de representación interna me hace vomitar un poco en mi boca.El tipo
T
que utiliza para representar una lente se define internamente comoEn consecuencia, para
get
el valor de una lente, debe enviar un valor indefinido para el argumento 'a'. Esto me parece una implementación increíblemente fea y ad hoc.Dicho esto, Henning ha incluido la plomería template-haskell para generar automáticamente los accesos para usted en un paquete separado ' data-accessor-template '.
Tiene el beneficio de un conjunto de paquetes decentemente grandes que ya lo emplean, siendo Haskell 98 y proporcionando la
Category
instancia más importante , por lo que si no prestas atención a cómo se hace la salchicha, este paquete es en realidad una opción bastante razonable .lentes
A continuación, está el paquete de lentes , que observa que una lente puede proporcionar un homomorfismo de mónada de estado entre dos mónadas de estado, definiendo lentes directamente como tales homomorfismos de mónada.
Si realmente se molestara en proporcionar un tipo para sus lentes, tendrían un tipo de rango 2 como:
Como resultado, prefiero este enfoque, ya que innecesariamente te saca de Haskell 98 (si quieres que un tipo proporcione a tus lentes en abstracto) y te priva de la
Category
instancia de lentes, lo que te permitiría componerlos con.
. La implementación también requiere clases de tipo multiparamétricas.Tenga en cuenta que todas las otras bibliotecas de lentes mencionadas aquí proporcionan algún combinador o pueden usarse para proporcionar este mismo efecto de focalización de estado, por lo que no se gana nada codificando su lente directamente de esta manera.
Además, las condiciones secundarias establecidas al comienzo no tienen realmente una buena expresión en esta forma. Al igual que con 'fclabels', esto proporciona un método de plantilla-haskell para generar automáticamente lentes para un tipo de registro directamente en el paquete principal.
Debido a la falta de
Category
instancias, la codificación barroca y el requisito de template-haskell en el paquete principal, esta es mi implementación menos favorita.lente de datos
[Editar: a partir de 1.8.0, estos han pasado del paquete de transformadores comonad a lentes de datos]
Mi
data-lens
paquete proporciona lentes en términos de la tienda Comonad.dónde
Ampliado esto es equivalente a
Puede ver esto como factorizar el argumento común del getter y el setter para devolver un par que consiste en el resultado de recuperar el elemento, y un setter para volver a poner un nuevo valor. Esto ofrece el beneficio computacional que el 'setter' aquí puede reciclar parte del trabajo utilizado para obtener el valor, lo que permite una operación de 'modificación' más eficiente que en la
fclabels
definición, especialmente cuando los accesores están encadenados.También hay una buena justificación teórica para esta representación, porque el subconjunto de valores de 'Lente' que satisfacen las 3 leyes establecidas al comienzo de esta respuesta son precisamente aquellas lentes para las cuales la función envuelta es un 'comonad coalgebra' para la tienda comonad . Esto transforma 3 leyes peludas para una lente
l
en 2 equivalentes sin puntos:Este enfoque se observó y describió por primera vez en Russell O'Connor's
Functor
esLens
comoApplicative
esBiplate
: Presentación de Multiplate y se escribió en un blog basado en una preimpresión de Jeremy Gibbons.También incluye una serie de combinadores para trabajar estrictamente con lentes y algunas lentes estándar para contenedores, como
Data.Map
.Por lo tanto, las lentes en
data-lens
forma aCategory
(a diferencia dellenses
paquete), son Haskell 98 (a diferencia defclabels
/lenses
), son cuerdas (a diferencia del extremo posterior dedata-accessor
) y proporcionan una implementación un poco más eficiente,data-lens-fd
proporciona la funcionalidad para trabajar con MonadState para aquellos dispuestos a salir de Haskell 98, y la maquinaria template-haskell ahora está disponible a través dedata-lens-template
.Actualización 28/06/2012: otras estrategias de implementación de lentes
Lentes de isomorfismo
Hay otras dos codificaciones de lentes que vale la pena considerar. El primero ofrece una buena forma teórica de ver una lente como una forma de dividir una estructura en el valor del campo y "todo lo demás".
Dado un tipo para isomorfismos
tal que los miembros válidos satisfagan
hither . yon = id
, yyon . hither = id
Podemos representar una lente con:
Estos son principalmente útiles como una forma de pensar sobre el significado de las lentes, y podemos usarlos como una herramienta de razonamiento para explicar otras lentes.
Lentes van Laarhoven
Podemos modelar lentes de manera que puedan componerse
(.)
eid
, incluso sin unaCategory
instancia, utilizandocomo el tipo de nuestras lentes.
Entonces definir una lente es tan fácil como:
y puede validar por sí mismo que la composición de la función es la composición de la lente.
Recientemente he escrito sobre cómo puede generalizar aún más las lentes van Laarhoven para obtener familias de lentes que pueden cambiar los tipos de campos, simplemente generalizando esta firma a
Esto tiene la desafortunada consecuencia de que la mejor manera de hablar sobre lentes es usar polimorfismo de rango 2, pero no es necesario usar esa firma directamente al definir lentes.
El
Lens
que definí anteriormente para_2
es en realidad unLensFamily
.He escrito una biblioteca que incluye lentes, familias de lentes y otras generalizaciones que incluyen captadores, colocadores, pliegues y recorridos. Está disponible en hackage como el
lens
paquete.Una vez más, una gran ventaja de este enfoque es que los mantenedores de bibliotecas pueden crear lentes de este estilo en sus bibliotecas sin incurrir en ninguna dependencia de la biblioteca de lentes, simplemente suministrando funciones con tipo
Functor f => (b -> f b) -> a -> f a
, para sus tipos particulares 'a' y 'b'. Esto reduce en gran medida el costo de la adopción.Como no es necesario utilizar el paquete para definir nuevas lentes, me quita mucha presión de mis preocupaciones anteriores sobre mantener la biblioteca Haskell 98.
fuente
:->
data-accessor
, y luego se lo pasé a Henning y dejé de prestarle atención. Laa -> r -> (a,r)
representación también me hace sentir incómodo, y mi implementación original fue igual que suLens
tipo. Heeennnninngg !!