2011-09-28 9 views
3

나는 Andrew Birkett의 블로그 Applicative arrows for XML &&& return to pure에서 화살표와 응용 펑터를 섞을 수 있다고 읽었습니다.적용 가능한 펑터와 화살표를 결합하는 방법

나는 내 자신으로 해봤지만 기대했던 바가 없다. 나는이 결과 싶습니다

[Scenario {scenario = "11111", origin = "333", alarm = "Sonde1"}, 
Scenario {scenario = "22222", origin = "444", alarm = "Sonde2"}] 

을하지만 난이 대신받을 :

[Scenario {scenario = "11111", origin = "333", alarm = "Sonde1"}, 
Scenario {scenario = "11111", origin = "333", alarm = "Sonde2"}, 
Scenario {scenario = "11111", origin = "444", alarm = "Sonde1"}, 
Scenario {scenario = "11111", origin = "444", alarm = "Sonde2"}, 
Scenario {scenario = "22222", origin = "333", alarm = "Sonde1"}, 
Scenario {scenario = "22222", origin = "333", alarm = "Sonde2"}, 
Scenario {scenario = "22222", origin = "444", alarm = "Sonde1"}, 
Scenario {scenario = "22222", origin = "444", alarm = "Sonde2"}] 

내가 거기에 내 코드에서 트위스트는하지만 난 곳을 검색 모른다 생각합니다.

누구나 도움을 제안 할 수 있다면 아래 코드를 참고하십시오.

{-# LANGUAGE Arrows, NoMonomorphismRestriction #-} 

import Text.XML.HXT.Core 
import Control.Applicative 
import Text.XML.HXT.Arrow.ReadDocument 
import Data.Maybe 
import Text.XML.HXT.XPath.Arrows 
import Text.Printf 


data Scenario = Scenario 
    { scenario, origin, alarm :: String 
    } 
    deriving (Show, Eq) 


xml= "<DATAS LANG='en'>\ 
    \ <SCENARIO ID='11111'>\ 
    \ <ORIGIN ID='333'>\ 
    \  <SCENARIO_S ERR='0'></SCENARIO_S>\ 
    \  <SCENARIO_S ERR='2'></SCENARIO_S>\ 
    \  <ALARM_M NAME='Sonde1'></ALARM_M>\ 
    \ </ORIGIN>\ 
    \ </SCENARIO>\ 
    \ <SCENARIO ID='22222'>\ 
    \ <ORIGIN ID='444'>\ 
    \  <SCENARIO_S ERR='10'></SCENARIO_S>\ 
    \  <SCENARIO_S ERR='12'></SCENARIO_S>\ 
    \  <ALARM_M NAME='Sonde2'></ALARM_M>\ 
    \ </ORIGIN>\ 
    \ </SCENARIO>\ 
    \</DATAS>" 

parseXML string = readString [ withValidate no 
         , withRemoveWS yes -- throw away formating WS 
         ] string 


parseVal tag name = WrapArrow $ getXPathTrees (printf "/DATAS/%s" tag) >>> getAttrValue name 

parseDatas = unwrapArrow $ Scenario <$> parseVal "SCENARIO"  "ID" 
           <*> parseVal "SCENARIO/ORIGIN"  "ID" 
           <*> parseVal "SCENARIO/ORIGIN/ALARM_M"  "NAME" 

testarr1= runX (parseXML xml >>> parseDatas) 
+3

추가 유형은 무슨 일이 일어나고 있는지 이해하는 데 도움이 될 것입니다

대신이 내가 코드를 변경 할 방법이다. 두 필드가 각각 3 개인 필드가 있고 2^3 = 8 결과를 얻었음에 유의하십시오. 이것은리스트 모나드가 작동하는 방식 때문입니다 - 그것은 당신에게 데카르트 제품을줍니다. – rampion

+0

감사합니다. 내가 틀린 곳을 찾아내는 데 약간의 시간이 걸렸고, 효과적으로 여기에 적용 할 수있는 펑터를 더 잘 이해하게되었습니다. 지금 올바른 코드가 없습니다. XML 구조를 더 잘 일치하도록 내 데이터 구조를 변경해야 할 수도 있습니다. –

+4

기본 인스턴스 대신 zipList 응용 프로그램 인스턴스가 필요하다고 생각합니다. –

답변

1

도망자에 의해 지적 되었 듯이 문제는 목록 모나드가 응용 프로그램과 함께 작동하는 방식입니다. 이것 봐 :

λ *Main > (+) <$> [1,2,3] <*> [1,2,3] 
[2,3,4,3,4,5,4,5,6] 

결과는 (+)의 carthesian 제품 [1,2,3] 및 [1,2,3] 적용 : 결과리스트 9 개 요소를 갖는다.

코드에서 parseVal "SCENARIO" "ID"은 2 개의 요소 목록을 반환하므로 parseVal "SCENARIO/ORIGIN" "ID"parseVal "SCENARIO/ORIGIN/ALARM_M" "NAME"이됩니다. 따라서 결과에는 8 개의 요소가 있습니다.

--- parse a generic tag 
parseVal tag name = WrapArrow $ getXPathTrees (printf "%s" tag) >>> getAttrValue name 

--- parse a "SCENARIO" xml element 
parseScenario = unwrapArrow $ Scenario 
     <$> (WrapArrow $ getAttrValue "ID") 
     <*> (parseVal "SCENARIO/ORIGIN" "ID") 
     <*> (parseVal "SCENARIO/ORIGIN/ALARM_M" "NAME") 

--- parse the XML, extract a list of SCENARIOS and, for each, apply parseScenario 
testarr1= runX (parseXML xml >>> getXPathTrees (printf "/DATAS/SCENARIO") >>> parseScenario) 

결과가 원하는대로입니다 :

λ *Main > testarr1 
[Scenario {scenario = "11111", origin = "333", alarm = "Sonde1"},Scenario {scenario = "22222", origin = "444", alarm = "Sonde2"}]