xml - sobre - Dar parámetros a la función de flecha en Haskell
if en haskell ejemplos (1)
Tengo un archivo XML con algunos datos. Este archivo tiene una descripción de las columnas y los datos en sí. Puedo leer los nombres de las columnas, pero no puedo leer los datos porque no entiendo cómo asignar los nombres de estas a una función que devolverá los datos.
Archivo XML:
<?xml version="1.0" encoding="UTF-8"?>
<Document>
<Header>
<Project code="SOME PROJECT" label="PROJECT LABEL"></Project>
<Datatable name="LOG" label="Visits"></Datatable>
<Columns>
<column name="study" label="Study" ordinal="1" type="TEXT"></column>
<column name="site" label="Site" ordinal="2" type="INTEGER"></column>
<column name="number" label="Subject" ordinal="3" type="INTEGER"></column>
<column name="visit" label="Visit number" ordinal="4" type="CHARACTER VARYING(20)">
</column>
<column name="vdate" label="Visit date (dd/mm/yyyy)." ordinal="5" type="CHARACTER VARYING(10)"></column>
</Columns>
</Header>
<table xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<row>
<study>Some study</study>
<site>1</site>
<number>1</number>
<visit>1</visit>
<vdate>28/12/2010</vdate>
</row>
<row>
<study>Some study</study>
<site>1</site>
<number>1</number>
<visit>2</visit>
<vdate>03/03/2011</vdate>
</row>
<row>
<study>Some study</study>
<site>1</site>
<number>1</number>
<visit>3</visit>
<vdate>09/06/2011</vdate>
</row>
</table>
</Document>
Código de muestra:
{-# LANGUAGE Arrows #-}
import Text.XML.HXT.Core
import Data.Tree.NTree.TypeDefs
parseXML :: String -> IOStateArrow s b XmlTree
parseXML file = readDocument [ withValidate yes
, withRemoveWS yes
] file
atTag :: ArrowXml a => String -> a (NTree XNode) XmlTree
atTag tag = deep (isElem >>> hasName tag)
text :: ArrowXml cat => cat (NTree XNode) String
text = getChildren >>> getText
getRowsData :: ArrowXml cat => cat (NTree XNode) [String]
getRowsData = atTag "table" >>>
proc l -> do
row <- atTag "row" -< l
study <- text <<< atTag "study" -< row
site <- text <<< atTag "site" -< row
returnA -< [study,site]
readTable :: ArrowXml t => t (NTree XNode) [[String]]
readTable =
proc l -> do
rows <- listA getRowsData -< l
returnA -< rows
main :: IO ()
main = do
res <- runX ( parseXML "log.xml" >>> readTable )
print res
El problema para mí está en getRowsData
. En el código de ejemplo, di los nombres de las columnas de forma implícita, pero quiero que se lean de una lista, se apliquen en la función de flecha y vuelvan las filas.
import Control.Arrow
Combinación de listas de flechas
Creo que lo que estás buscando es una forma de combinar varias flechas en la misma entrada para mostrar su resultado:
list :: Arrow a => [a b c] -> a b [c]
list [] = returnA >>^ const []
list (a:as) = (a &&& list as) >>^ uncurry (:)
(a &&& list as)
devuelve un par de la cabeza y la cola, luego aplicamos >>^
la función pura uncurry (:) :: (x,[x]) -> [x]
para recombinarlos.
Vamos a probarlo. Aquí hay algunas cosas para jugar con las flechas IO. Una mónada es una flecha, pero debes envolverla en su categoría Kleisli. runKleisli
desenvuelve de nuevo para que pueda ejecutarlo, pero me lleva demasiado tiempo escribir, así que he usado una versión infijo >$>
para alimentarlo con la entrada:
ask :: Kleisli IO String String
ask = Kleisli $ /xs -> putStrLn xs >> getLine
(>$>) = runKleisli
Entonces ahora es más fácil interactuar:
*Main> ask >$> "Hello?"
Hello?
Hello!
"Hello!"
y la list
funciona bien:
*Main> list [ask,ask] >$> "say something!"
say something!
OK
say something!
What do you want me to say?
["OK","What do you want me to say?"]
De [String] a la flecha que devuelve [String]
Pero desea convertir una lista de cadenas en una flecha que produce listas de cadenas.
appList :: Arrow a => (s -> a b c) -> [s] -> a b [c]
appList f xs = list (map f xs)
Podemos probar eso con una variante en la prueba de pregunta:
askRespond xs = Kleisli $ /thx -> do
putStrLn xs
ans <- getLine
putStrLn thx
return ans
Así que podemos ver que appList
está funcionando de la manera que desea, al hacer una flecha de cada cadena y ejecutar cada una, combinando las respuestas en una cadena de nuevo:
*Main> appList askRespond ["What''s your name?","What''s your favourite colour?","Would you like some cheese?"] >$> "Thanks."
What''s your name?
Andrew
Thanks.
What''s your favourite colour?
Green
Thanks.
Would you like some cheese?
Yes - could I have gruyere?
Thanks.
["Andrew","Green","Yes - could I have gruyere?"]
Agarrando múltiples contenidos de etiquetas
Ahora apliquemos eso a su problema.
Primero, hagamos una taquigrafía para hacer una flecha de una cuerda:
textAtTag xs = text <<< atTag xs
Entonces usemos la appList
:
getRowsData = atTag "table"
>>> atTag "row"
>>> appList textAtTag ["study","site"]
No he probado ese último, ¡por favor revisa!