递归搜索记录属性并收集到 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 a
是 Monoid
只要 a
是 Monoid
:
instance Monoid a => Monoid (Maybe a)
因此,我们可以map
每个PageContent
到一个Maybe [ServiceRequest]
和mconcat
他们。
PageElement
有一个services :: Maybe [ServiceRequest]
,但在body :: Maybe [PageContent]
下面可能还有更多的Maybe [ServiceRequest]
。我们可以在主体上使用 getPageContentServiceRequests
,使用 >>=
连接将要引入的两个级别的 Maybe
,并使用 <>
(又名 mappend
)用 services
附加它们。我们可以对 PageComponent
和 PageConditional
:
做同样的事情
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)
您好,我正在尝试了解如何收集(可能)深度嵌套的数据结构的相同属性。以下数据类型为
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 a
是 Monoid
只要 a
是 Monoid
:
instance Monoid a => Monoid (Maybe a)
因此,我们可以map
每个PageContent
到一个Maybe [ServiceRequest]
和mconcat
他们。
PageElement
有一个services :: Maybe [ServiceRequest]
,但在body :: Maybe [PageContent]
下面可能还有更多的Maybe [ServiceRequest]
。我们可以在主体上使用 getPageContentServiceRequests
,使用 >>=
连接将要引入的两个级别的 Maybe
,并使用 <>
(又名 mappend
)用 services
附加它们。我们可以对 PageComponent
和 PageConditional
:
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)