Подтвердить что ты не робот

Запуск Haskell HXT за пределами IO?

Все примеры, которые я видел до сих пор с помощью инструментария Haskell XML, HXT, используют runX для выполнения анализатора. runX выполняется внутри монады IO. Есть ли способ использовать этот синтаксический анализатор XML вне IO? Кажется, это чистая операция для меня, не понимаю, почему я вынужден быть внутри IO.

4b9b3361

Ответ 1

Вы можете использовать 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

Ответ 2

Ответ Тревиса Брауна был очень полезен. Я просто хочу добавить свое собственное решение здесь, которое, я думаю, немного более общее (используя те же функции, просто игнорируя проблемы, связанные с конкретными проблемами).

Я ранее рассыпался с:

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

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