Я хочу решить свою конкретную потребность, поэтому продемонстрирую идею на простом примере:
Типы данных:
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
Проблема:
Я хотел бы сгруппировать activities
в соответствии с предикатами, которым они удовлетворяют. Есть ли какой-либо стандартный шаблон Haskell, который я могу использовать для решения этой проблемы? Решение должно обеспечивать удобный доступ к произвольной группе, удовлетворяющей предикату (конечно, тогда мне придется обрабатывать каждую из них по-своему).
Я был бы признателен за любую информацию по этому поводу.
П.Д.: Это одна из моих попыток:
groupByCriteria :: [a -> Bool] -> [a] -> [(a -> Bool, [a])]
groupByCriteria ps acts = [(p, filter p acts) | p <- ps]
Однако я бы предпочел иметь метку String
, указывающую, какой предикат выполняется, а не функцию (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]
Большое спасибо ! Мне интересно, что происходит с деятельностью, которая удовлетворяет как предикату 1, так и 2, например: Activity {activityName = "Attend project meeting", purpose = Work, timeOfDay = Afternoon, location = Office}])
. Есть ли у вас какие-нибудь мысли? Я вижу, что порядок предикатов имеет значение.
В идеале для общего решения мне нужно было бы доказать, что решения, которым удовлетворяет каждый из предикатов, не имеют общих элементов, я думаю? Эти наборы дадут непересекающийся союз. Не уверен, что это решаемо.
Или дайте список всех предикатов, удовлетворяющих каждому действию.
@F.Zer Если вам нужна гарантия того, что предикаты не перекрываются, предикаты — неправильный инструмент. Вам нужен тип перечисления, в котором перечислены категории, и функция классификации, помещающая каждый элемент в категорию.
Спасибо @amalloy, это звучит великолепно! Не будет ли функция классификации предикатом?
@F.Zer Предикат возвращает true или false.
@amalloy Конечно, да. Я некорректно выразился. Разве функция классификации не будет содержать предикат? Если да, то как я могу быть уверен, что эти условия не совпадают?
@F.Zer Возможно, вам следует задать отдельный вопрос о группировке действий в непересекающиеся наборы.
Хорошо, @amalloy. В этом есть смысл.
Возможно, создать тип данных с именем и предикатом?