递归搜索记录属性并收集到 Haskell 中的列表

Recursively search for a record attribute and collect into list in 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 时,该元素可能有一个 _body,它有一个 Maybe [PageContent],因此遍历 PageElement 的 _body 应该与遍历原始 [ PageContent] 列表传入,假设我从 Maybe 中提取它。

我很难弄清楚如何 return 将其作为新列表

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

所以我可能没有 ServiceRequest,或者我可能有 1 个或多个 ServiceRequest 的列表。如果我递归地这样做,我会把两个列表传递给函数吗?一个带有 [PageContent],然后是一个空列表,我可以在收集 ServiceRequest 时递归添加它?

例子

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

这是正确的方法吗?当我使用相同类型的列表时,我觉得我理解递归概念,但如果我必须构建一个具有不同类型的全新列表,我就不理解了。

Maybe aMonoid 只要 aMonoid:

instance Monoid a => Monoid (Maybe a)

因此,我们可以map每个PageContent到一个Maybe [ServiceRequest]mconcat他们。

PageElement有一个services :: Maybe [ServiceRequest],但在body :: Maybe [PageContent]下面可能还有更多的Maybe [ServiceRequest]。我们可以在主体上使用 getPageContentServiceRequests,使用 >>= 连接将要引入的两个级别的 Maybe,并使用 <>(又名 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)