HXT: Can input change using arrow syntax?

With the following code

{-# LANGUAGE Arrows #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
import Text.XML.HXT.Core

parseXml :: IOSArrow XmlTree XmlTree
parseXml = getChildren >>> getChildren >>>
  proc x -> do
    y <- x >- hasName "item"
    returnA -< x

main :: IO ()
main = do
    person <- runX (readString [withValidate no]
                    "<xml><item>John</item><item2>Smith</item2></xml>"
                    >>> parseXml)
    putStrLn $ show person
    return ()

I get a conclusion

[NTree (XTag "item" []) [NTree (XText "John") []]]

So it seems to have hasName "item"been applied to x, which I did not expect. Using arrowp , I get for parseXml:

parseXml
   = getChildren >>> getChildren >>>
      (arr (\ x -> (x, x)) >>>
         (first (hasName "item") >>> arr (\ (y, x) -> x)))

So I have a arrow chart

                                                       y
                                   /-- hasName "item" ---
                               x  /                       
-- getChildren -- getChildren ---\x->(x,x)              \(y,x)->x --- final result
                                  \                       / 
                                   \---------------------/  

Why is it hasName "item"also applied to the second place of the tuple? I thought that there is no state in haskell, but it hasName "item" xreturns a new object instead of changing the internal state x.

Related question: Is factoring an arrow from an arrow a sign of a valid transformation?

My initial problem

I have the following code:

{-# LANGUAGE Arrows #-}
import Text.XML.HXT.Core

data Person = Person { forname :: String, surname :: String } deriving (Show)

parseXml :: IOSArrow XmlTree Person
parseXml = proc x -> do
    forname <- x >- this /> this /> hasName "fn" /> getText
    surname <- x >- this /> this /> hasName "sn" /> getText
    returnA -< Person forname surname

main :: IO ()
main = do
    person <- runX (readString [withValidate no]
                               "<p><fn>John</fn><sn>Smith</sn></p>"
                    >>> parseXml)
    putStrLn $ show person
    return ()

If I run it, everything works fine and I get output

[Person {forname = "John", surname = "Smith"}]

But if I change parseXmlto avoid operatorsthis

parseXml :: IOSArrow XmlTree Person
parseXml = (getChildren >>> getChildren) >>> proc x -> do
    forname <- x >- hasName "fn" /> getText
    surname <- x >- hasName "sn" /> getText
    returnA -< Person forname surname

( []).

parseXml :: IOSArrow XmlTree Person
parseXml = (getChildren >>> getChildren) >>>
  proc x -> do
    forname <- x >- withTraceLevel 5 traceTree >>> hasName "fn" /> getText
    surname <- x >- hasName "sn" /> getText
    returnA -< Person forname surname

content of: 
============

---XTag "fn"
   |
   +---XText "John"



content of: 
============

---XTag "sn"
   |
   +---XText "Smith"


[]

, ,

parseXml :: IOSArrow XmlTree Person
parseXml = (getChildren >>> getChildren) >>>
  proc x -> do
    forname <- x >- hasName "fn" /> getText
    surname <- x >- withTraceLevel 5 traceTree >>> hasName "sn" /> getText
    returnA -< Person forname surname

content of: 
============

---XTag "fn"
   |
   +---XText "John"


[]

, x . , hasName "fn" x, surname. x ?

+1
2

, , .

proc x -> do
  y <- x >- hasName "item"
  returnA -< x

- , , item.

hasName "item" `guards` this

{-# LANGUAGE Arrows #-}
{-# LANGUAGE NoMonomorphismRestriction #-}

module Main where

import Text.XML.HXT.Core

parseXml0 :: IOSArrow XmlTree XmlTree
parseXml0 = getChildren >>> getChildren >>>
  proc x -> do
    _ <- hasName "item" -< x
    returnA -< x

parseXml1 :: IOSArrow XmlTree XmlTree
parseXml1 = getChildren >>> getChildren >>>
            (hasName "item" `guards` this)

main1 :: Show c => IOSArrow XmlTree c -> IO ()
main1 parseXml = do
    person <- runX (readString [withValidate no]
                    "<xml><item>John</item><item2>Smith</item2></xml>"
                    >>> parseXml)
    putStrLn $ show person
    return ()

main :: IO ()
main = main1 parseXml0 >> main1 parseXml1
+2

EDIT: , !

:

x

  • (getText) (this /> this), "fn" (hasName "fn"), forname
  • (getText) (this /> this), "sn" (hasName "sn"), surname
  • yield Person forname surname

, , , , , , , . "<p><fn>John</fn><sn>Smith</sn><fn>Anne</fn><sn>Jones</sn></p>", . .

:

x

  • x "fn", forname ( x)
  • x "sn", surname ( x)

"fn" "sn"! , .

, . , . "fn", .

EDIT: ( ) .

import Control.Monad ((>=>))

data XML = Text String | Tag String [XML] deriving Show

this :: a -> [a]
this = return

(/>) :: (a -> [XML]) -> (XML -> [c]) -> a -> [c]
f /> g = f >=> getChildren >=> g

(>--) :: a -> (a -> b) -> b
x >-- f = f x

getChildren :: XML -> [XML]
getChildren (Text _) = []
getChildren (Tag _ c) = c

hasName :: String -> XML -> [XML]
hasName _ (Text _) = []
hasName n i@(Tag n' _) = if n == n' then [i] else []

getText :: XML -> [String]
getText (Text t) = [t]
getText (Tag _ _) = []

parseXML :: XML -> [(String, String)]
parseXML = \x -> do
  forname <- x >-- (this /> this /> hasName "fn" /> getText)
  surname <- x >-- (this /> this /> hasName "sn" /> getText)
  return (forname, surname)

parseXMLBroken :: XML -> [(String, String)]
parseXMLBroken = getChildren >=> getChildren >=> \x -> do
  forname <- x >-- (hasName "fn" /> getText)
  surname <- x >-- (hasName "sn" /> getText)
  return (forname, surname)

runX :: (XML -> a) -> XML -> a
runX f xml = f (Tag "/" [xml])

xml :: XML
xml = (Tag "p" [ Tag "fn" [Text "John"]
               , Tag "sn" [Text "Smith"] ])

example1 = runX parseXML xml

example2 = runX parseXMLBroken xml

*Main> example1
[("John","Smith")]
*Main> example2
[]
+1

Source: https://habr.com/ru/post/1533873/


All Articles