1

Haskell パッケージ hxt の使用法は、私にとってはまだ少し不思議です。特にアロー表記とその結果の型は魔法です。

主に 2 つの部分からなる XML ファイルを処理したい。1 つはオブジェクトの定義を保持し、2 番目はオブジェクトの使用法/目的を保持します。まず、パート 1 で Haskell データ構造を取得するための hxt 処理を記述し、その後パート 2 を処理し、最後にプログラムの実際のロジックで読み込まれた両方のデータ構造を結合します。

矢印のチュートリアルのおかげで、ファイルの処理は一般的に問題ありません。しかし、次の 3 つのステップを実行する 1 つの do 表記を使用したいと思います。ドキュメントを読み取り (遅延)、結果の構造を最初のプロセッサで 1 回処理し、同じ構造を 2 番目のプロセッサで再度処理します。私が望まないのは、次の例のように「readDocument」を 2 回呼び出すことです。

import Text.XML.HXT.Core
import Data.Char(toUpper)
import Data.Tree.NTree.TypeDefs

play filename = do 
                  results <- runX (getAllAddresses filename) 
                  results2 <- runX (getAllAddressesUsages filename) 
                  print results 
                  print results2 



getAllAddresses :: FilePath -> IOSArrow XmlTree [(String,NTree XNode)]
getAllAddresses filename =
    readDocument [withValidate no] filename >>>
    getChildren >>>
    isElem >>> hasName "main" >>>
    getChildren >>>
    isElem >>> hasName "part1" >>>
    getChildren >>>
    isElem >>> hasName "address" >>>
    listA(getAddress)                 -- create a list for each variable, so use listA



getAddress :: IOSArrow XmlTree (String,NTree XNode)
getAddress =
    getChildren >>>
    isElem >>>
         (
          neg ( hasName "location") >>>   -- all elements being no "location"
          getName &&& (getChildren)       -- get the name and the value for each element
         ) 
    <+>     
    ( 
      hasName "location" >>>              -- work on all nodes within the  "location" subcontainer
      getChildren >>> 
      isElem >>>
      ( getName &&& (getChildren) )       -- get the name and the value for each element
     )




getAllAddressesUsages :: FilePath -> IOSArrow XmlTree [(String,NTree XNode)]
getAllAddressesUsages filename =
    readDocument [withValidate no] filename >>>
    getChildren >>>
    isElem >>> hasName "main" >>>
    getChildren >>>
    isElem >>> hasName "part2" >>>
    getChildren >>>
    listA(getAddressUsagePurpose2)                 -- create a list for each variable, so use listA

getAddressUsagePurpose2 :: IOSArrow XmlTree (String,NTree XNode)
getAddressUsagePurpose2 =
    hasName "use_obj-names_for_purpose_2" >>>            -- work on all nodes with usage 2
    ( getName &&& (getChildren) )                        -- get the name and the value for each element

サンプルデータ:

<main>
 <part1>
  <address>
    <obj-name>one</obj-name>
    <name>peter 1</name>
    <street>streetname 1</street>
    <location>
      <country>Germany</country>
      <state>Baden Wuerttemberg</state>
   </location>
   </address>
  <address>
    <obj-name>two</obj-name>
    <name>peter 2</name>
    <street>streetname 2</street>
    <location>
      <country>Germany</country>
      <state>Nordrhein Westfalen</state>
      </location>
   </address>
 </part1>
 <part2>
   <use_obj-names_for_purpose_1>
     <obj-name>two</obj-name>
   </use_obj-names_for_purpose_1>
   <use_obj-names_for_purpose_2>
     <obj-name>two</obj-name>
   </use_obj-names_for_purpose_2>
 </part2>
</main>

したがって、正式な質問は次のとおりです。

次のようなものを得るために、関数 play のモナド do はどのように見えますか?

readXmlDocument :: String -> IOSArrow XmlTree (NTree XNode)
readXmlDocument filename = readDocument [withValidate no] filename

play filename = do 
             document <- readXmlDocument filename
             allAddresses <- getAllAddresses document
             allPurposes <- getAllAddressesUsages document
             result <- processLogics allAddresses allPurposes 
             print result

モナドからアロウズへ、モナドへ戻り、プレーンデータへ、さらにモナドへ戻るにはどうすればよいでしょうか。

そして、なぜ私はそれをどのように行うのですか?

4

1 に答える 1

1

この問題の 1 つの解決策は次のとおりです。

Arrow 言語拡張機能を使用し、「proc」式を使用して、1 つの関数で読み込まれたドキュメントを 2 つのプロセッサ パスで処理します。結果はタプルに結合されます。それでも、このタプルには、実行する必要がある 2 つの Arrow が含まれています。これは、runX 関数の 2 つのアプリケーションによって行われます。

それでも、ボットの結果が次の計算で結合されると、この構成によってファイルが 1 回または 2 回読み込まれるかどうかは正確にはわかりません。

{-# LANGUAGE Arrows #-}

import Text.XML.HXT.Core
import Data.Char(toUpper)
import Data.Tree.NTree.TypeDefs


play filename = (runX addresses, runX usages)
    where (addresses,usages)=(analyseXml (readXmlDocument filename))

analyseXml :: IOSArrow XmlTree (NTree XNode) -> (IOSArrow XmlTree [(String,NTree XNode)],IOSArrow XmlTree String)
analyseXml = proc document -> do 
               allAddresses <- getAllAddresses -< document
               allUsages <- getAllAddressesUsages -< document
               returnA -< (allAddresses,allUsages)

readXmlDocument :: String -> IOSArrow XmlTree (NTree XNode)
readXmlDocument filename = readDocument [withValidate no] filename



getAllAddresses :: IOSArrow XmlTree (NTree XNode) -> IOSArrow XmlTree [(String,NTree XNode)]
getAllAddresses document =
    document >>>
    getChildren >>>
    isElem >>> hasName "main" >>>
    getChildren >>>
    isElem >>> hasName "part1" >>>
    getChildren >>>
    isElem >>> hasName "address" >>>
    listA(getAddress)                 -- create a list for each variable, so use listA



getAddress :: IOSArrow XmlTree (String,NTree XNode)
getAddress =
    getChildren >>>
    isElem >>>
         (
          neg ( hasName "location") >>>   -- all elements being no "location"
          getName &&& (getChildren)       -- get the name and the value for each element
         ) 
    <+>     
    ( 
      hasName "location" >>>              -- work on all nodes within the  "location" subcontainer
      getChildren >>> 
      isElem >>>
      ( getName &&& (getChildren) )       -- get the name and the value for each element
     )




getAllAddressesUsages :: IOSArrow XmlTree (NTree XNode) -> IOSArrow XmlTree String
getAllAddressesUsages document =
    document >>>
    getChildren >>>
    isElem >>> hasName "main" >>>
    getChildren >>>
    isElem >>> hasName "part2" >>>
    getChildren >>>
    isElem >>> hasName "use_obj-names_for_purpose_2" >>>
    getChildren >>>
    isElem >>> hasName "obj-name" >>>
    getChildren >>>
    getText                 -- create a list with objects for each short-name. So use listA

実行は次のように行うことができます。

*Main>  snd ( play  "../tmp/haskell/test.xml")
["two"]

*Main>  fst ( play  "../tmp/haskell/test.xml")
[[("obj-name",NTree (XText "one") []),("name",NTree (XText "peter 1") []),("street",NTree (XText "streetname 1") []),("country",NTree (XText "Germany") []),("state",NTree (XText "Baden Wuerttemberg") [])],[("obj-name",NTree (XText "two") []),("name",NTree (XText "peter 2") []),("street",NTree (XText "streetname 2") []),("country",NTree (XText "Germany") []),("state",NTree (XText "Nordrhein Westfalen") [])]]
*Main>
于 2013-02-24T23:02:36.137 に答える