Запуск 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

Я полностью согласен с ним в том, что выполнение этого дает вам меньше контроля над конфигурацией синтаксического анализатора и т. Д., Что вызывает сожаление.

Другие вопросы по тегам