haskell hxt

¿Ejecutar Haskell HXT fuera de IO?



(2)

Todos los ejemplos que he visto hasta ahora utilizando el kit de herramientas de Haskell XML, HXT, utilizan runX para ejecutar el analizador. runX corre dentro de la mónada IO. ¿Hay alguna forma de usar este analizador XML fuera de IO? Me parece que es una operación pura, no entiendo por qué me veo obligado a estar dentro de IO.


La respuesta de Travis Brown fue muy útil. Solo quiero agregar mi propia solución aquí, que creo que es un poco más general (usando las mismas funciones, simplemente ignorando los problemas específicos del problema).

Anteriormente me estaba deshaciendo con:

upIO :: XmlPickler a => String -> IO [a] upIO str = runX $ readString [] str >>> arrL (maybeToList . unpickleDoc xpickle)

que pude cambiar a esto:

upPure :: XmlPickler a => String -> [a] upPure str = runLA (xreadDoc >>> arrL (maybeToList . unpickleDoc xpickle)) str

Estoy completamente de acuerdo con él en que hacer esto te da menos control sobre la configuración del analizador, etc., lo cual es desafortunado.


Puede usar el xread de xread junto con runLA para analizar una cadena XML fuera de IO .

xread tiene el siguiente tipo:

xread :: ArrowXml a => a String XmlTree

Esto significa que puede componerlo con cualquier flecha de tipo (ArrowXml a) => a XmlTree Whatever para obtener a String Whatever .

runLA es como runX , pero para cosas de tipo LA :

runLA :: LA a b -> a -> [b]

LA es una instancia de ArrowXml .

Para poner todo esto junto, la siguiente versión de mi respuesta a su pregunta anterior utiliza HXT para analizar una cadena que contiene XML bien formado sin ningún IO involucrado:

{-# LANGUAGE Arrows #-} module Main where import qualified Data.Map as M import Text.XML.HXT.Arrow classes :: (ArrowXml a) => a XmlTree (M.Map String String) classes = listA (divs >>> pairs) >>> arr M.fromList where divs = getChildren >>> hasName "div" pairs = proc div -> do cls <- getAttrValue "class" -< div val <- deep getText -< div returnA -< (cls, val) getValues :: (ArrowXml a) => [String] -> a XmlTree (String, Maybe String) getValues cs = classes >>> arr (zip cs . lookupValues cs) >>> unlistA where lookupValues cs m = map (flip M.lookup m) cs xml = "<div><div class=''c1''>a</div><div class=''c2''>b</div>/ /<div class=''c3''>123</div><div class=''c4''>234</div></div>" values :: [(String, Maybe String)] values = runLA (xread >>> getValues ["c1", "c2", "c3", "c4"]) xml main = print values

classes y getValues son similares a la versión anterior, con algunos cambios menores para adaptarse a la entrada y salida esperadas. La principal diferencia es que aquí usamos xread y runLA lugar de readString y runX .

Sería bueno poder leer algo así como un ByteString perezoso de una manera similar, pero por lo que sé, esto no es posible actualmente con HXT.

Algunas otras cosas: puede analizar cadenas de esta manera sin IO , pero probablemente sea mejor usar runX siempre que pueda: le da más control sobre la configuración del analizador, mensajes de error, etc.

También: traté de hacer que el código en el ejemplo fuera sencillo y fácil de extender, pero los combinadores en Control.Arrow y Control.Arrow.ArrowList hacen que trabajar con flechas sea mucho más conciso si lo desea. La siguiente es una definición equivalente de classes , por ejemplo:

classes = (getChildren >>> hasName "div" >>> pairs) >. M.fromList where pairs = getAttrValue "class" &&& deep getText