Pergunta

Estou tentando chegar a um acordo com a caixa de ferramentas XML da Haskell (Hxt) E estou atingindo uma parede em algum lugar, porque pareço não entender completamente as setas como uma ferramenta computacional.

Aqui está o meu problema, que eu esperava ilustrar um pouco melhor usando uma sessão do 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]

Então Parse é uma pequena função auxiliar que aplica qualquer seta que eu dê ao documento XML trivial

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

Defino outra função auxiliar, desta vez para extrair o texto abaixo de um nó com um determinado nome:

> 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")]

Com a ajuda desta função, é fácil usar o &&& Combinador para emparelhar o texto de dois nós diferentes e, em seguida, digamos, passe para um construtor, como este:

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

Agora vem a parte que não entendo: quero fator esquerdo! extract chamadas getChildren no nó raiz duas vezes. Em vez disso, eu gostaria que apenas chamasse uma vez! Então eu recebo o filho do nó raiz

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

Observe que eu tentei reordenar as chamadas para, digamos, iselem etc. para descobrir se esse é o problema. Mas, como está, eu simplesmente não tenho idéia de por que isso não está funcionando. Há um 'tutorial' de flecha no wiki Haskell E a maneira como eu entendi, isso deve ser possível fazer o que eu quero fazer dessa maneira - ou seja, usar &&& Para emparelhar os resultados de dois cálculos.

Também funciona-mas apenas no início da cadeia de flecha, não no meio do caminho, quando já tenho alguns resultados, que quero manter 'compartilhado'. Tenho a sensação de que não sou capaz de envolver a cabeça em torno de uma diferença de idéias entre composição normal da função e notação de seta. Eu apreciaria muito qualquer indicação! (Mesmo que seja apenas para alguma flecha genérica que fica um pouco mais profunda do que o no Haskell-wiki.)

Obrigada!

Foi útil?

Solução

Se você converter a seta para (e depois de) uma versão determinística, isso funciona conforme o esperado:

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

Isso não é realmente satisfatório, porém, e não me lembro do topo da minha cabeça, por que (&&&) se comporta dessa maneira com uma flecha não determinística (eu usaria pessoalmente o proc/do notação para qualquer coisa muito mais complicada do que isso).


ATUALIZAR: Parece haver algo estranho acontecendo aqui com runLA e xread. Se você usar runX e readString Tudo funciona como esperado:

> 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")]

Isso significa que você tem que executar o analisador no IO Mônada, mas há vantagens em usar runX Enfim (melhores mensagens de erro, etc.).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top