【问题标题】:Overloading Functions with Pattern Matching?使用模式匹配重载函数?
【发布时间】:2021-10-27 23:07:45
【问题描述】:

Haskell 粉丝大家好!

我所有的问题都与 -- OVERLOADED(?) FUNCTION -- 部分有关,为了完整起见,我包括了其余部分。

  1. 我想知道使用模式匹配来重载我的函数 order 是否有意义,就像我在下面的示例中所做的那样。

  2. 我还想知道 order 函数的第一个版本中调用函数“checkBalance balance”的第一个函数是否总是得到 executerd(因为我没有为它指定模式)或从不(因为所有的 Food 模式都包含在下面的函数中)。

在此先感谢初学者:)

-- 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

【问题讨论】:

  • order 没有过载。各个定义只是 order x = case x of (O {}, balance) -> ... 之类的语法糖。
  • 所以我写的基本上是一个覆盖在语法糖中的 switch 语句?有没有更优雅的方式来将不同的订单与指定类型的食物进行分支?

标签: haskell pattern-matching overloading


【解决方案1】:

我看不出这个函数定义有什么问题。

函数子句按顺序尝试,所以总是先尝试checkBalance的第一个分支,然后再尝试下一个保护,以此类推,如果第一组的保护都没有匹配,则下一组将尝试 (O Indian {} _ _)。

如果第一组的守卫是穷尽的,那么下面的其他分支就无法到达,这意味着有问题,但没有更多细节很难说更多。

【讨论】:

  • 好吧,在后面带有点 (| ...) 的部分中没有更多详细信息,因为我想在实施任何进一步的东西之前知道执行顺序是如何工作的。因此,如果我想根据 Food 类型分别为每个订单函数实现一些东西,那么单独删除每个订单函数中的第一个订单函数和 checkBalance 会更有意义吗?
【解决方案2】:
-- OVERLOADED(?) FUNCTION --
order :: (Order, CreditBalance) -> OrderStatus
order (O {}, balance)
  | not (checkBalance balance ) = Declined
  | ...

上面的模式将涵盖所有情况,任何低于它的东西都没有机会检查。

原因是Order只有一个构造函数,即O,而(O {})匹配O构造函数的所有可能参数。元组的另一个成员只是一个简单的Int,它总是匹配。

由于模式是从上到下匹配并选择第一个匹配的,因此它们在代码中的定义顺序很重要。如果您将最广泛的模式放在顶部,下面更具体的模式将永远没有机会匹配。

至于重载函数,我可以想到如何(ab)使用模式匹配来模仿 OOP 中的函数重载,但是您还需要(ab)使用数据声明和整个类型系统来弯曲它们遵循这样的想法,这只会让事情变得更糟。

【讨论】:

  • 所以基本上你的意思是一阶函数是穷举的(只是为了我的理解)?在订单的食物类型单独匹配的每个函数中删除第一个函数和 checkBalance 是否更有意义?
  • 是的,你是绝对正确的。第一种模式是详尽的。是的,我会从狭窄的模式转向更广泛的模式。将其视为if elif elif elif else 构造,其中第一个真正的分支运行,最后一个是包罗万象的模式(如果之前的那些尚未涵盖所有内容)。
  • 好吧,有道理!有没有比模式匹配更优雅的方法来处理这种分支,或者这是一种好的做法?我一直在努力为这个特定程序寻找解决方案,因为如果你明白我的意思,Food 是一种按类型顺序“包装”的类型。
  • 我认为模式匹配非常适合这种情况。
  • 第一种情况并不详尽,除非有像| otherwise 这样的包罗万象的守卫。如果守卫没有涵盖所有情况,则将考虑其他模式。我认为 OP 想要表达“如果您没有足够的钱或其他与美食无关的事情出错,请先处理它;否则,请通过特定于美食的处理”,正如 OP 所写的那样,这将正常工作。
猜你喜欢
  • 1970-01-01
  • 2013-08-27
  • 1970-01-01
  • 2011-09-29
  • 2016-12-20
  • 1970-01-01
  • 2023-03-21
  • 2014-12-22
  • 2012-09-02
相关资源
最近更新 更多