Acabo de encontrar Const
en la documentación de Control.Applicative
, pero me es difícil calcular dónde es útil, simplemente usando Monoid
directamente.¿Para qué sirve el functor aplicativo 'Const'?
¿Qué me estoy perdiendo?
Acabo de encontrar Const
en la documentación de Control.Applicative
, pero me es difícil calcular dónde es útil, simplemente usando Monoid
directamente.¿Para qué sirve el functor aplicativo 'Const'?
¿Qué me estoy perdiendo?
Es bastante útil cuando se combina con Traversable
.
getConst . traverse Const :: (Monoid a, Traversable f) => f a -> a
Esa es la receta general para englobar 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 por el estilo generalizada elem
elem :: Eq x => x -> Term x -> Bool
hacer ocurrir-comprobación de un Traversable Term
parametrizada por la representación de variables libres. Seguí cambiando la representación de Term
y estaba harto de modificar un trillón de funciones, algunas de las cuales estaban haciendo acumulaciones, en lugar de mapeos efectivos. Me alegré de encontrar una abstracción que cubriera ambos.
Es útil cuando tiene una función o estructura de datos que funciona para todos (Applicative
) Functor
s, y desea reutilizarlo en un sentido degenerado. Es análogo a pasar const
o id
a funciones que funcionan con funciones arbitrarias.
Van Laarhoven lenses se definen en términos de Functors arbitrarias, y el uso Const
para derivar un descriptor de acceso de campo (y el igualmente trivial Identity
para derivar un actualizador de campo).
Traversable
tipos, como menciones pigworker, son otro ejemplo de esto.
Como menciona dave4420, implementar el accesorio y el actualizador para lentes Van Laarhoven implica Const
functor. 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 Gabriel González señala, Const se utiliza para proporcionar Compuestos absorbentes para 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 travesías, necesita el comportamiento Aplicativo completo, y se convierte en lo que el trabajador del cerdo describe en otra respuesta.
http://www.soi.city.ac.uk/~ross/papers/Applicative.html sección 4 es una buena referencia para el truco transversal –
No 'foldMap id' produce el mismo resultado con menos restricciones ('Plegable' en lugar de' Traversable')? –
De hecho, es por eso que 'Plegable' existe. Sin embargo, es bastante útil que todo 'Traversable' sea' Plegable', siendo la anterior la construcción de 'foldMapDefault'. Enchufe: SHE admite 'DefaultSuperclassInstances', de modo que todo' Traversable' se establece de forma predeterminada por silencioso como 'Plegable'. – pigworker