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
モナドからアロウズへ、モナドへ戻り、プレーンデータへ、さらにモナドへ戻るにはどうすればよいでしょうか。
そして、なぜ私はそれをどのように行うのですか?