一連の基準によるオブジェクトのグループ化

概要

特定のニーズを解決したいので、簡単な例を使用してそのアイデアを示します。

データ型:

data Activity = Activity
  { activityName :: String
  , purpose :: Purpose
  , timeOfDay :: TimeOfDay
  , location :: Location
  }
  deriving (Show, Eq)

data Purpose = Work | Personal | Leisure
  deriving (Show, Eq)

data TimeOfDay = Morning | Afternoon | Evening
  deriving (Show, Eq)

data Location = Home | Office | Elsewhere
  deriving (Show, Eq)

例:

activities =
  [ Activity "Check emails" Work Morning Office
  , Activity "Attend project meeting" Work Afternoon Office
  , Activity "Go for a run" Leisure Afternoon Elsewhere
  , Activity "Prepare dinner" Personal Evening Home
  , Activity "Watch a movie" Leisure Evening Home
  , Activity "Read a book" Leisure Evening Home
  ]

述語:

isWorkRelated :: Activity -> Bool
isWorkRelated activity = purpose activity == Work

isAfternoonActivity :: Activity -> Bool
isAfternoonActivity activity = timeOfDay activity == Afternoon

isAtHome :: Activity -> Bool
isAtHome activity = location activity == Home

問題:

満たす述語に従ってアクティビティをグループ化したいと考えています。それを解決するために使用できる標準的な Haskell パターンはありますか?このソリューションにより、述語を満たす任意のグループに簡単にアクセスできるようになります (もちろん、その場合、それぞれを別の方法で処理する必要があります)。

これについて何か洞察があれば幸いです。

PD: これは私の試みの 1 つです。

groupByCriteria :: [a -> Bool] -> [a] -> [(a -> Bool, [a])]
groupByCriteria ps acts = [(p, filter p acts) | p <- ps]

ただし、関数 (a -> Bool) ではなく、どの述語が満たされるかを示す文字列ラベルを使用したいと考えています。

解決策

次のようにしてデータ型を変更するだけです。

data Group a = Group String (a -> Bool)

isWorkRelated :: Group Activity
isWorkRelated = Group "work-related" (\activity -> purpose activity == Work)

isAfternoonActivity :: Group Activity
isAfternoonActivity = Group "afternoon" (\activity -> timeOfDay activity == Afternoon)

isAtHome :: Group Activity
isAtHome = Group "at-home" (\activity -> location activity == Home)

次に、次のようにグループ化します。

groupByCriteria :: [Group a] -> [a] -> [(String, [a])]
groupByCriteria ps acts = [(name, filter p acts) | Group name p <- ps]