haskell - sirven - tipos de lentes para leer
Usando una lente para leer mĂșltiples campos (2)
Al resolver la respuesta anterior de danidiaz , pude construir un Getter Prisoner (String, Int, Int)
usando ReifiedGetter
:
getNameRankAndCerealNumber_2 :: Prisoner -> (String, Int, Int)
getNameRankAndCerealNumber_2 = p ^. nameRankAndCerealNumber_2
nameRankAndCerealNumber_2 :: Getter Prisoner (String, Int, Int)
nameRankAndCerealNumber_2 = runGetter ((,,) <$> Getter name <*> Getter rank <*> Getter (cereal.number))
Y un Lens'' Prisoner (String, Int, Int)
usando al alongside
, aunque tuve que construir manualmente Iso''
''s entre Prisoner
y HList [String, Int, Int]
y entre HList [a,b,c]
y (a,b,c)
.
getNameRankAndCerealNumber_3 :: Prisoner -> (String, Int, Int)
getNameRankAndCerealNumber_3 p = p ^. nameRankAndCerealNumber_3
setNameRankAndCerealNumber_3 :: (String, Int, Int) -> Prisoner -> Prisoner
setNameRankAndCerealNumber_3 t p = p & nameRankAndCerealNumber_3 .~ t
nameRankAndCerealNumber_3 :: Lens'' Prisoner (String, Int, Int)
nameRankAndCerealNumber_3 = hlist . alongside id (alongside id number) . triple
where triple :: Iso'' (a,(b,c)) (a,b,c)
triple = dimap (/(a,(b,c)) -> (a,b,c)) (fmap $ /(a,b,c) -> (a,(b,c)))
hlist :: Iso'' Prisoner (String, (Int, Cereal))
hlist = dimap (/(P n r c) -> (n,(r,c))) (fmap $ /(n,(r,c)) -> P n r c)
Puede haber una forma más fácil de hacer esto, pero esa es otra pregunta.
Dados los tipos
data Prisoner = P { _name :: String
, _rank :: Int
, _cereal :: Cereal }
data Cereal = C { _number :: Int
, _percentDailyValue :: Map String Float
, _mascot :: String }
Podría extraer el nombre, rango y número de cereal de alguien mediante la coincidencia de patrones:
getNameRankAndCerealNumber_0 :: Prisoner -> (String, Int, Int)
getNameRankAndCerealNumber_0 (P { _name=name
, _rank=rank
, _cereal = C { _number=cerealNumber }}
) = (name, rank, cerealNumber)
Alternativamente, podría usar lentes para extraer cada parte por separado
makeLenses ''''Cereal
makeLenses ''''Prisoner
getNameRankAndCerealNumber_1 :: Prisoner -> (String, Int, Int)
getNameRankAndCerealNumber_1 p = (p ^. name, p ^. rank, p ^. cereal.number)
¿Hay una manera de extraer los tres simultáneamente en un solo recorrido de la estructura de datos?
¿Alguna forma de combinar Getter
s, Getter sa -> Getter sb -> Getter s (a,b)
?
Podemos usar la instancia ReifiedGetter
del ReifiedGetter
tipo de ReifiedGetter de Control.Lens.Reified
:
runGetter $ (,) <$> Getter number <*> Getter mascot
En general, los nuevos tipos en Control.Lens.Reified
ofrecen una gran cantidad de instancias muy útiles para getters y fold.
Nota n. ° 1 : observe que estamos combinando las lentes como captadores y obteniendo un captador a cambio. No se puede obtener una lente compuesta de esta manera, ya que habría problemas si sus "enfoques" se superponen. ¿Cuál podría ser el comportamiento apropiado del colocador en ese caso?
Nota n. ° 2 : la función alongside permite combinar dos lentes, obteniendo una lente auténtica que funciona en las dos mitades de un producto. Esto es diferente del caso anterior porque podemos estar seguros de que las lentes no se superponen. alongside
es útil cuando su tipo es una tupla o tiene un isomorfismo en una tupla.