Me interesaría un pequeño ejemplo de van Laarhoven's isomorphism lenses, aplicado a un tipo de datos como data BValue = BValue { π :: Float, σ :: Float, α :: Float } deriving Show
(específicamente, las funciones get/set/modify). Gracias de antemano.Isomorfismo lentes
Respuesta
Desde el puesto de van Laarhoven, el tipo Lens
es
data Lens a b = forall r . Lens (Iso a (b, r))
Así que en nuestro caso es a
BValue
y queremos construir algunos leneses que captan a cabo uno o más de los elementos. Entonces, por ejemplo, construyamos una lente que elija π.
piLens :: Lens BValue Float
así que va a ser una lente de una BValue
a un Float
piLens = Lens (Iso {fw = piFwd, bw = piBwd})
Una lente selecciona dos cosas (es decir, la primera de ellas en el triple, con pi etiqueta.): Un residuo tipo r
(se omite aquí porque no tenemos que especificar explícitamente un tipo existencial en haskell), y un isomorfismo. Un isomorfismo a su vez se compone de una función hacia delante y hacia atrás.
piFwd :: BValue -> (Float, (Float, Float))
piFwd (BValue {pi, sigma, alpha}) = (pi, (sigma, alpha))
La función de reenvío simplemente aísla el componente que queremos. Tenga en cuenta que mi tipo residual aquí es el "resto del valor", es decir, un par de flotadores sigma y alfa.
piBwd :: (Float, (Float, Float)) -> BValue
piBwd (pi, (sigma, alpha)) = BValue { pi = pi, sigma = sigma, alpha = alpha }
La función hacia atrás es análoga.
Así que ahora hemos definido una lente para manipular el componente pi de un BValue
.
Las otras siete lentes son similares. (7 lentes: elija sigma y alfa, elija todos los pares posibles (sin tener en cuenta el orden), seleccione todos BValue
y elija ()
).
El único aspecto del que no estoy seguro es el rigor: me preocupa un poco que las funciones fw y bw que he escrito sean demasiado estrictas. No es seguro.
No hemos terminado aún:
todavía tenemos que comprobar que en realidad piLens
respeta las leyes de la lente. Lo bueno de la definición de van Laarhoven de Lens
es que solo debemos verificar las leyes de isomorfismo; las leyes de lentes siguen a través del cálculo en su publicación de blog.
Así que nuestras obligaciones de prueba son:
fw piLens . bw piLens = id
bw piLens . fw piLens = id
Ambas pruebas se siguen directamente de las definiciones de piFwd
y piBwd
y leyes sobre la composición.
Consulte , que implementa lentes para tipos de registro.
Para ilustrar este paquete, tomemos los siguientes dos tipos de datos de ejemplo.
import Data.Label import Prelude hiding ((.), id) data Person = Person { _name :: String , _age :: Int , _isMale :: Bool , _place :: Place } data Place = Place { _city , _country , _continent :: String }
Ambos tipos de datos son tipos de registro con todas las etiquetas con un guion bajo. Este guión bajo es una indicación para nuestro código Template Haskell para derivar lentes para estos campos. Las lentes Derivadas se pueden hacer con este simple revestimiento:
$(mkLabels [''Person, ''Place])
Para todas las etiquetas se creará una lente.
Ahora veamos este ejemplo. Este compañero de 71 años de edad, mi vecino llamó Ene, no le importaba usándolo como un ejemplo:
jan :: Person jan = Person "Jan" 71 True (Place "Utrecht" "The Netherlands" "Europe")
Cuando queremos estar seguros de Jan es realmente tan viejo como él afirma que podemos utilizar la función get para obtener la edad como un número entero:
hisAge :: Int hisAge = get age jan
Considere que ahora quiere mudarse a Amsterdam: qué mejor lugar para pasar sus viejos días. El uso de la composición que puede cambiar el valor de la ciudad en el interior de la estructura:
moveToAmsterdam :: Person -> Person moveToAmsterdam = set (city . place) "Amsterdam"
Y ahora:
ghci> moveToAmsterdam jan Person "Jan" 71 True (Place "Amsterdam" "The Netherlands" "Europe")
composición se realiza mediante el operador que es parte del módulo Control.Category (.). Asegúrese de importar este módulo y ocultar la función de identificación predeterminada (.) Del Preludio de Haskell.
- 1. Isomorfismo de gráfico
- 2. Isomorfismo de Curry-Howard
- 3. ¿Para qué sirven las lentes /?
- 4. Algoritmos para la detección de isomorfismo subgráfico
- 5. Aplicación práctica de "Plátanos, lentes, sobres y alambre de púas"?
- 6. Evitar la repetición usando lentes mientras profundamente copiar en asignar los valores de
- 7. graph - ¿Cómo uso Tree Isomorphic para resolver el emparejamiento de patrones de lenguaje?
- 8. Lista de bibliotecas de C++ para la teoría de grafos
- 9. ¿Cómo "enlazar" una estructura de datos persistente a una GUI en Scala?
- 10. Scalaz Lens Composición
- 11. ¿Qué considerar al escribir para la pantalla táctil?
- 12. Acceso a los controles de la cámara USB con AForge
- 13. framework MVC en Haskell
- 14. haskell: ¿hay alguna forma de generar instancias "derivadas" para tipos de datos aproximadamente tuple-isomórficos?
- 15. Tabla de unión vacía resultante de JPA ManyToMany
- 16. Registro valor predeterminado sintaxis de descriptor de acceso
- 17. ¿Qué placa de desarrollo elige para procesamiento de imágenes múltiples en tiempo real?
- 18. adaptación de búsqueda de texto para algoritmos de comparación gráfico/molécula
- 19. ¿Cómo uso accept_nested_attributes_for?
Una última cosa: no hay funciones get/set/modify para 'BValue'. Las funciones get/set/modify se definen una vez y siguen para cada tipo de 'Lens a b'. (Ver la publicación del blog). Lo único que queda por hacer es aplicar, por ejemplo, 'get' a un objetivo específico adaptado a su tipo de datos. Entonces: 'get piLens' es el getter para el campo pi de' BValue'. – Lambdageek
¿Cómo se utilizarían estos accesadores en una variable específica del tipo dado, por ejemplo, 'bv :: BValue'? La lente se aplica a un tipo, por lo que debería ser posible 'obtener' o 'establecer' los campos de una variable que pertenece al tipo. –
@mindbound solo aplica la función get/set/modify a la lente y al valor: 'get piLens bv' o' modify piLens (+ 1.0) bv' – Lambdageek