Home > Back-end >  Overloading Functions with Pattern Matching?
Overloading Functions with Pattern Matching?

Time:10-28

Hello fellow Haskell Fans!

All my questions are about the -- OVERLOADED(?) FUNCTION -- part, I included the rest for completeness.

  1. I was wondering if it makes sense to use Pattern Matching to Overload my function order like I did in my example below.

  2. I was also wondering if the first function with the function call "checkBalance balance" in the first version of the order function always gets executerd (because I didn't sepcify a pattern for it) or never (because all the patterns of Food are covered in the functions below).

Thanks in advance from a beginner :)

-- 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) -> OrderStatus
order (O {}, balance)
  | not (checkBalance balance ) = Declined
  | ...

order (O Indian {} _ _, _)
  | ...

order (O Pasta {} _ _, _)
  | ...

order (O Chinese {} _ _, _)
  | ...

-- ANOTHER FUNCTION --
checkBalance :: CreditBalance -> Bool
checkBalance balance
  | balance > 100 = True
  | otherwise = False

CodePudding user response:

I can't see anything really wrong with that function definition.

Function clauses are tried in order, so that first branch with checkBalance will always be tried first, and the next guard, and so on, and if none of the guards of the first group is matched, then the next group will be tried (O Indian {} _ _).

If the guards of the first group were exhaustive, then the other branches below would not be reachable, which would mean something is wrong but it's hard to say more without more details.

CodePudding user response:

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

The above pattern will cover every case and anything below it will never have the opportunity to check.

Reason is that Order has only one constructor, namely O, and (O {}), matches all possible arguments to the O constructor. The other member of the tuple is just a simple Int which always matches.

Since patterns are matched from top to bottom and the first that matches is chosen, the ordering of their definition in code is important. If you put the broadest possible pattern at the top, the more specific ones below will never have the opportunity to match.

As for overloading function, I can think of how one could (ab)use pattern matching to imitate function overloading as in OOP, but then you would also need to (ab)use data declarations and the whole type system to bend them to conform to such an idea and this would just make things worse.

  • Related