Lentes funcionales

80

¿Alguien podría explicarme los lentes funcionales? Es un tema sorprendentemente difícil para Google y no he progresado. Todo lo que sé es que proporcionan una funcionalidad de obtención / configuración similar a la de OO.

Misa
fuente
7
Hay una buena introducción a las lentes de Edward Kmett en YouTube. Los ejemplos están en Scala, pero no debería ser demasiado difícil de seguir.
Hammar
Sí, intenté verlos, pero tener suficiente tiempo mientras todavía estoy alerta, no es tan fácil: P
Masse
2
@Jochen: Los lentes descritos allí no tienen mucho en común con los lentes de los que trata esta pregunta.
sclv
3
Aquí hay una buena introducción usando imágenes: Lentes en imágenes .
Debjit el

Respuestas:

61

Una lente consta de dos funciones, una captadora y una fijadora:

data Lens a b = Lens { getter :: a -> b, setter :: b -> a -> a }

Por ejemplo, podríamos tener lentes para la primera y segunda parte de un par:

fstLens :: Lens (a, b) a
fstLens = Lens fst $ \x (a, b) -> (x, b)

sndLens :: Lens (a, b) b
sndLens = Lens snd $ \x (a, b) -> (a, x)

La verdadera conveniencia de las lentes es que componen:

compose :: Lens b c -> Lens a b -> Lens a c
compose f g = Lens (getter f . getter g) $
                   \c a -> setter g (setter f c (getter g a)) a

Y se convierten mecánicamente en Statetransiciones:

lensGet :: MonadState s m => Lens s a -> m a
lensGet = gets . getter

lensSet :: MonadState s m => Lens s b -> b -> m ()
lensSet f = modify . setter f

lensMod :: MonadState s m => Lens s b -> (b -> b) -> m ()
lensMod f g = modify $ setter f =<< g . getter f

(+=) :: (MonadState s m, Num b) => Lens s b -> b -> m ()
f += x = lensMod f (+ x)
Apocalipsis
fuente
Su ejemplo de redacción no se revisó a máquina. GHC infiere; Lens aa -> Lens aa -> Lens aa
Masse
Masse: accidentalmente volteé fy g.
Apocalisp
Todavía no escribe check en a-> c. Se infiere en componer :: Lens ab -> Lens aa -> Lens ab
Masse