Запуск Haskell HXT вне IO?
Все примеры, которые я видел до сих пор с использованием инструментария Haskell XML, HXT, используют runX
выполнить парсер. runX
работает внутри монады IO. Есть ли способ использовать этот синтаксический анализатор XML вне IO? Кажется, это чистая операция для меня, не понимаю, почему я вынужден быть внутри IO.
2 ответа
Вы можете использовать HXT xread
вместе с runLA
разобрать строку XML вне IO
,
xread
имеет следующий тип:
xread :: ArrowXml a => a String XmlTree
Это означает, что вы можете составить его с любой стрелкой типа (ArrowXml a) => a XmlTree Whatever
чтобы получить a String Whatever
,
runLA
как runX
, но для вещей типа LA
:
runLA :: LA a b -> a -> [b]
LA
это пример ArrowXml
,
Чтобы собрать все это вместе, следующая версия моего ответа на ваш предыдущий вопрос использует HXT для анализа строки, содержащей правильно сформированный XML, без какого-либо IO
участвует:
{-# 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
а также getValues
аналогичны предыдущей версии, с небольшими изменениями, которые соответствуют ожидаемому вводу и выводу. Основное отличие состоит в том, что здесь мы используем xread
а также runLA
вместо readString
а также runX
,
Было бы неплохо иметь возможность читать что-то вроде ленивого ByteString
аналогичным образом, но, насколько я знаю, в настоящее время это невозможно с HXT.
Пара других вещей: вы можете разобрать строки таким образом без IO
, но, вероятно, лучше использовать runX
всякий раз, когда вы можете: это дает вам больше контроля над конфигурацией парсера, сообщениями об ошибках и т. д.
Также: я попытался сделать код в примере простым и легким для расширения, но комбинаторы в Control.Arrow
а также Control.Arrow.ArrowList
Позволяет работать со стрелками гораздо более кратко, если хотите. Ниже приведено эквивалентное определение classes
, например:
classes = (getChildren >>> hasName "div" >>> pairs) >. M.fromList
where pairs = getAttrValue "class" &&& deep getText
Ответ Трэвиса Брауна был очень полезным. Я просто хочу добавить свое собственное решение здесь, которое я считаю более общим (с использованием тех же функций, просто игнорируя проблемы, связанные с конкретной проблемой).
Раньше я был заправлен:
upIO :: XmlPickler a => String -> IO [a]
upIO str = runX $ readString [] str >>> arrL (maybeToList . unpickleDoc xpickle)
который я смог изменить на это:
upPure :: XmlPickler a => String -> [a]
upPure str = runLA (xreadDoc >>> arrL (maybeToList . unpickleDoc xpickle)) str
Я полностью согласен с ним в том, что выполнение этого дает вам меньше контроля над конфигурацией синтаксического анализатора и т. Д., Что вызывает сожаление.