HXT: лево-факторинг недетерминистые стрелки?

StackOverflow https://stackoverflow.com/questions/4220316

  •  26-09-2019
  •  | 
  •  

Вопрос

Я пытаюсь прийти к срокам с XML Toolbox Haskell (HXT.) И я где-то куда ударяю стену, потому что я не полностью понимаю стрелки как вычислительный инструмент.

Вот моя проблема, которую я надеялся иллюстрировать немного лучше, используя сеанс GHCI:

> let parse p = runLA (xread >>> p) "<root><a>foo</a><b>bar</b><c>baz</c></root>"
> :t parse
parse :: LA XmlTree b -> [b]

Таким образом, анализ - это небольшая функция помощника, которая применяет любую стрелкой, которую я даю в тривиальном документе XML

<root>
  <a>foo</a>
  <b>bar</b>
  <c>baz</c>
</root>

Я определяю другую функцию помощника, на этот раз, чтобы извлечь текст ниже узла с указанным именем:

> let extract s = getChildren >>> isElem >>> hasName s >>> getChildren >>> getText 
> :t extract
extract :: (ArrowXml cat) =>
   String -> cat (Data.Tree.NTree.TypeDefs.NTree XNode) String
> parse (extract "a" &&& extract "b") -- extract two nodes' content.
[("foo","bar")]

С помощью этой функции легко использовать &&& Комбинатор для соединения текста двух разных узлов, а затем, скажем, пропустите его конструктору, как это:

> parse (extract "a" &&& extract "b" >>^ arr (\(a,b) -> (b,a))) 
[("bar","foo")]

Теперь приходит часть, которую я не понимаю: я хочу покинуть фактор! extract вызовы getChildren на корневом узле дважды. Вместо этого я бы хотел, чтобы это позвонить только один раз! Поэтому я впервые получаю ребенка корневого узла

> let extract' s = hasName s >>> getChildren >>> getText
> :t extract'
extract' :: (ArrowXml cat) => String -> cat XmlTree String
> parse (getChildren >>> isElem >>> (extract' "a" &&& extract' "b"))
[]

Обратите внимание, что я пытался заказать звонки, скажем, ISELEM и т. Д. Для того, чтобы узнать, если это проблема. Но, как это стоит, у меня просто нет идеи, почему это не работает. Есть стрелка «Учебник» на Haskell Wiki И так, как я понял это, это должен быть возможным делать то, что я хочу сделать это - а именно использовать &&& Для того, чтобы соединить результаты двух вычислений.

Это тоже работает - но только в начале цепочки стрелки, а не в середине рупота, когда у меня уже есть некоторые результаты, которые я хочу сохранить «общий». У меня есть ощущение, что я просто не смогу обернуть голову вокруг разницы в идеях между нормальной функциональной композицией и ноуткой стрелкой. Я был бы очень признателен любым указателям! (Даже если это только для некоторой универсальной стрелкой, который идет немного более глубоко, чем на Haskell-Wiki.)

Спасибо!

Это было полезно?

Решение

Если вы преобразуете стрелку в (а затем из) детерминированной версии, это работает как ожидалось:

> let extract' s = unlistA >>> hasName s >>> getChildren >>> getText
> parse (listA (getChildren >>> isElem) >>> (extract' "a" &&& extract' "b"))
[("foo","bar")]

Это не совсем удовлетворительное, хотя, и я не могу вспомнить из головы, почему (&&&) ведет себя таким образом с недетерминированной стрелкой (я бы лично использовал proc/do нотация за что-то гораздо сложное, чем это).


ОБНОВИТЬ: Кажется, что-то странное происходит здесь с runLA а также xread. Отказ Если вы используете runX а также readString Все работает, как и ожидалось:

> let xml = "<root><a>foo</a><b>bar</b><c>baz</c></root>"
> let parse p = runX (readString [] xml >>> p)
> let extract' s = getChildren >>> hasName s >>> getChildren >>> getText
> parse (getChildren >>> isElem >>> (extract' "a" &&& extract' "b"))
[("foo","bar")]

Это означает, что вы должны запустить парсер в IO Монад, но есть преимущества использования runX В любом случае (лучшие сообщения об ошибках и т. Д.).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top