Перегрузка функций с помощью сопоставления шаблонов?

#haskell #pattern-matching #overloading

Вопрос:

Привет, дорогие поклонники Хаскелла!

Все мои вопросы касаются — ПЕРЕГРУЖЕННОГО(?) ФУНКЦИЯ-часть, остальное я включил для полноты картины.

  1. Мне было интересно, имеет ли смысл использовать сопоставление шаблонов для перегрузки моего порядка функций, как я сделал в приведенном ниже примере.
  2. Мне также было интересно, всегда ли первая функция с вызовом функции «Баланс баланса» в первой версии функции заказа получает executerd (потому что я не выделил для нее шаблон) или никогда (потому что все шаблоны продуктов питания описаны в функциях ниже).

Заранее спасибо от новичка 🙂

 -- TYPE DECLARATIONS -- data Spice = Regular | Medium | Hot data Base = Noodles | Rice data Meat = Duck | Chicken | Pork data Sauce = Tomato | Meatballs | Carbonara  data Food = Indian Spice | Pasta Sauce | Chinese Base Meat  data DeliveryOption = Pickup | Delivery  data DeliveryTime = Immediate | Later  type CreditBalance = Int  data Order = O Food DeliveryOption CreditBalance  data OrderStatus = Success | Pending | Declined  -- OVERLOADED(?) FUNCTION -- order :: (Order, CreditBalance) -gt; OrderStatus order (O {}, balance)  | not (checkBalance balance ) = Declined  | ...  order (O Indian {} _ _, _)  | ...  order (O Pasta {} _ _, _)  | ...  order (O Chinese {} _ _, _)  | ...  -- ANOTHER FUNCTION -- checkBalance :: CreditBalance -gt; Bool checkBalance balance  | balance gt; 100 = True  | otherwise = False  

Комментарии:

1. order не перегружен. Отдельные определения — это просто синтаксический сахар для чего-то подобного order x = case x of (O {}, balance) -gt; ... .

2. итак, то, что я написал, в основном является оператором переключения, покрытым синтаксическим сахаром? Есть ли более элегантный способ разделить различные заказы на определенные виды продуктов питания?

Ответ №1:

Я не вижу ничего действительно неправильного в этом определении функции.

Предложения функций опробованы по порядку, так что первая ветвь с checkBalance всегда будет опробована первой, а следующая охрана и так далее, и если ни одна из охранников первой группы не будет сопоставлена, то будет опробована следующая группа ( O Indian {} _ _ ).

Если бы стражи первой группы были исчерпывающими, то другие ветви ниже были бы недоступны, что означало бы, что что-то не так, но трудно сказать больше без более подробной информации.

Комментарии:

1. Ну, в деталях с защитой, за которыми следуют точки, больше нет деталей ( | ... ), потому что я хотел знать, как работает порядок выполнения, прежде чем внедрять какие-либо дополнительные функции. Поэтому, если бы я хотел реализовать некоторые функции для каждой функции заказа в зависимости от типа пищи по отдельности, было бы разумнее удалить функцию первого заказа и проверить баланс в каждой функции заказа по отдельности, верно?

Ответ №2:

 -- OVERLOADED(?) FUNCTION -- order :: (Order, CreditBalance) -gt; OrderStatus order (O {}, balance)  | not (checkBalance balance ) = Declined  | ...  

Приведенный выше шаблон будет охватывать каждый случай, и все, что ниже, никогда не будет иметь возможности проверить.

Причина в том, что Order имеет только один конструктор , а именно O , и (O {}) , соответствует всем возможным аргументам O конструктора. Другой член кортежа — это просто простой Int , который всегда совпадает.

Поскольку шаблоны сопоставляются сверху вниз и выбирается первый, который соответствует, порядок их определения в коде важен. Если вы поместите максимально широкий шаблон вверху, то более конкретные, приведенные ниже, никогда не смогут совпасть.

Что касается функции перегрузки, я могу подумать о том, как можно (ab)использовать сопоставление шаблонов для имитации перегрузки функций, как в ООП, но тогда вам также потребуется (ab)использовать объявления данных и всю систему типов, чтобы согнуть их в соответствии с такой идеей, и это только ухудшит ситуацию.

Комментарии:

1. Итак, по сути, вы хотите сказать, что функция первого порядка является исчерпывающей (только для моего понимания)? Было бы разумнее удалить эту первую функцию и проверить баланс в каждой функции, где тип питания заказа подбирается индивидуально ?

2. да, вы абсолютно правы. Первая схема является исчерпывающей. И да, я бы перешел от узких моделей к более широким. Посмотрите на это как на if elif elif elif else конструкцию, в которой выполняется первая истинная ветвь, а последняя-это всеобъемлющий шаблон (если предыдущие еще не охватили все).

3. ладно, в этом есть смысл! Есть ли более элегантный способ справиться с этим ветвлением, чем я сделал с сопоставлением шаблонов, или это хорошая практика? Я изо всех сил пытался найти решение для этой конкретной программы, потому что еда-это тип, «завернутый» в порядок типов, если вы понимаете, что я имею в виду.

4. Я думаю, что сопоставление шаблонов идеально подходит для этого случая.

5. Первый случай не является исчерпывающим, если только нет такого охранника, как | otherwise «цепочка». Если охранники не охватывают все случаи, то будут рассмотрены другие модели. Я думаю, что ОП хочет выразить «если у вас недостаточно денег или что-то другое, не зависящее от кухни, пойдет не так, сначала разберитесь с этим; в противном случае переходите к обработке, связанной с кухней», что будет работать нормально, как написал ОП.