data - monads learn you a haskell
¿Para qué sirve el funtor aplicativo ''Const''? (4)
Acabo de encontrar a Const
en la documentación de Control.Applicative
, pero me resulta difícil calcular dónde es útil, simplemente usando Monoid
directamente.
¿Qué me estoy perdiendo?
Como menciona dave4420, la implementación de accesores y actualizadores para lentes Van Laarhoven involucra el functor Const
. Elaborar:
{-# LANGUAGE Rank2Types #-}
import Control.Applicative
import Control.Monad.Identity
-- The definition of Van Laarhoven lenses:
type Lens a b = forall f . Functor f => (b -> f b) -> (a -> f a)
-- Getter passes the Const functor to the lens:
get :: Lens a b -> a -> b
get l = getConst . (l Const)
-- Updater passes the Identity functor to the lens:
modify :: Lens a b -> (b -> b) -> (a -> a)
modify l f = runIdentity . l (Identity . f)
set :: Lens a b -> b -> (a -> a)
set l r = modify l (const r)
-- Example: -------------------------------------------
data Person = Person { _name :: String, _age :: Int }
deriving Show
name :: Lens Person String
name f (Person n a) = fmap (/x -> Person x a) (f n)
age :: Lens Person Int
age f (Person n a) = fmap (/x -> Person n x) (f a)
main :: IO ()
main = do
let john = Person "John" 34
print $ get age john
print $ set name "Pete" john
Como señala Gabriel González, Const se usa para proporcionar a los Getters lentes. http://hackage.haskell.org/package/lens-tutorial-1.0.0/docs/Control-Lens-Tutorial.html . Ahí solo usas que Const es un functor.
Para los recorridos, necesita el comportamiento de Solicitud completo, y se convierte en lo que describe el trabajador porcino en otra respuesta.
Es útil cuando tiene una función o estructura de datos que funciona para todos los Functor
( Applicative
) y desea reutilizarla en un sentido degenerado. Es análogo a pasar const
o id
a funciones que funcionan dadas funciones arbitrarias.
Las lentes Van Laarhoven se definen en términos de Functors arbitrarios, y usan Const
para derivar un elemento de acceso a campo (y la Identity
igualmente trivial para derivar un actualizador de campo).
Traversable
tipos transitables, como lo menciona el trabajador porcino, son otro ejemplo de esto.
Es bastante útil cuando se combina con Traversable
.
getConst . traverse Const :: (Monoid a, Traversable f) => f a -> a
Esa es la receta general para juntar un montón de cosas juntas. Fue uno de los casos de uso que me convenció de que valía la pena separar Applicative
de Monad
. Necesitaba cosas como elem
generalizado
elem :: Eq x => x -> Term x -> Bool
para realizar la comprobación de ocurrencia de un Traversable Term
parametrizado por la representación de variables libres. Seguí cambiando la representación de Term
y estaba harto de modificar un millón de funciones transversales, algunas de las cuales estaban haciendo acumulaciones, en lugar de mapas efectivos. Me alegré de encontrar una abstracción que cubría ambos.