2017-11-24 13 views
1

こんにちは私は、おそらく深くネストされたデータ構造の同じアトリビュートをどのように収集するのかを考えています。次のデータ型は、レコード属性を再帰的に検索し、Haskellのリストに集める

data PageContent = 
PageElement { content_type :: String 
      , element :: String 
      , attributes :: Maybe Object 
      , services :: Maybe [ServiceRequest] 
      , body :: Maybe [PageContent] 
      , styles :: Maybe Object 
      , scripts :: Maybe Object } 
| PageComponent { content_type :: String 
       , id :: String 
       , tag :: Maybe String 
       , args :: Maybe Object 
       , services ::Maybe [ServiceRequest]} 
| PageConditional { content_type :: String 
        , true :: Maybe [PageContent] 
        , false :: Maybe [PageContent] 
        , condition :: String } 
deriving(Show) 

です。私の場合は、宣言されているすべてのServiceRequestを収集しようとしています。要素は[PageContent]のリストとして渡されます。再帰関数を使うと完璧だと思うのですが、たとえば、PageElementをヒットしたときに、その要素にPagebodyがあるかもしれない_bodyがある可能性があります。そのため、PageElementの_bodyは、元の[ PageContent]リストが渡されました。

私は苦労だから私は何のServiceRequestを持っていることができなかったか、私は1つの以上のServiceRequestsのリストを持っている可能性があり、私は新しいリストとしてこれを返すだろうか

getPageContentServiceRequests :: [PageContent] -> Maybe [ServiceRequest] 

を考え出すを持っています。これを再帰的に行うと、関数に2つのリストが渡されますか? 1つは[PageContent]とし、次にServiceRequestsを収集しながら再帰的に追加できる空のリストですか?

getPageContentServiceRequests (x:xs) (y:ys) = 
    case (isJust (body x)) of 
     True -> y : getPageContentServiceRequests fromJust (body x) ys 

は、これは正しいアプローチだろうか?私は同じタイプのリストで作業しているときに再帰的な概念を理解していると感じますが、別のタイプの完全に新しいリストを作成する必要はありません。

+1

'Maybe'は' [] '任意の要素を抽象化し、0または1を抽象化します。両方が必要なのですか? 'Just []'と 'Nothing'を区別する必要がありますか? – Zeta

+0

@ゼータは本当にありません。つまり、[PageContent] - > [a]ここで[a]は[ServiceRequest]または[]空のリストのいずれかです。 – Donna

+0

はい、あなたの 'PageComponent'や' PageElement'は 'Maybe [ServiceRequest]'の代わりに 'services :: [ServiceRequest]'を持つことができます。 – Zeta

答えて

2

Maybe aは限りaMonoidあるようMonoidです:

instance Monoid a => Monoid (Maybe a) 

したがって、私たちすることができますmapPageContentMaybe [ServiceRequest]mconcatそれらをします。

PageElementは、services :: Maybe [ServiceRequest]を有するが、body :: Maybe [PageContent]の下にさらにMaybe [ServiceRequest]を有することができる。身体にgetPageContentServiceRequestsを使用して、>>=を使用して、導入されるMaybeの2つのレベルを結合し、<>(別名mappend)にservicesを追加します。私たちは、PageComponentPageConditionalのために同じことを行うことができます。

import Data.Monoid 

getPageContentServiceRequests :: [PageContent] -> Maybe [ServiceRequest] 
getPageContentServiceRequests = mconcat . map getServiceRequests where 

    getServiceRequests :: PageContent -> Maybe [ServiceRequest] 
    getServiceRequests PageElement { services=services, body=body } = 
    services <> (body >>= getPageContentServiceRequests) 
    getServiceRequests PageComponent { services=services } = 
    services 
    getServiceRequests PageConditional { true=true, false=false } = 
    (true >>= getPageContentServiceRequests) <> 
    (false >>= getPageContentServiceRequests) 
+0

非常にこの明確で有益な答えをありがとう – Donna

関連する問題