使用模式匹配重载函数?
Overloading Functions with Pattern Matching?
大家好Haskell粉丝们!
我所有的问题都是关于 -- OVERLOADED(?) FUNCTION -- 部分,为了完整起见,我将其余部分包括在内。
我想知道使用模式匹配来重载我的函数 order 是否有意义,就像我在下面的示例中所做的那样。
我还想知道 order 函数的第一个版本中第一个带有函数调用“checkBalance balance”的函数是否总是被执行(因为我没有为其指定模式)或从不(因为 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
我看不出该函数定义有任何问题。
函数子句按顺序尝试,所以第一个带有 checkBalance
的分支总是先被尝试,然后是下一个守卫,依此类推,如果第一个守卫的 none匹配组,则尝试下一组(O Indian {} _ _
)。
如果第一组的守卫穷尽,那么下面的其他分支就无法到达,那就说明有问题,但不详细就不好说了。
-- OVERLOADED(?) FUNCTION --
order :: (Order, CreditBalance) -> OrderStatus
order (O {}, balance)
| not (checkBalance balance ) = Declined
| ...
上面的模式将涵盖所有情况,低于它的任何东西都没有机会检查。
原因是Order
只有一个构造函数,即O
,而(O {})
匹配所有可能的参数给O
构造函数。元组的另一个成员只是一个简单的 Int
,它始终匹配。
由于模式是从上到下匹配的,并且会选择第一个匹配的模式,因此它们在代码中的定义顺序很重要。如果您将尽可能广泛的模式放在顶部,那么下面更具体的模式将永远没有机会匹配。
至于重载函数,我可以想到如何(滥用)使用模式匹配来模仿 OOP 中的函数重载,但是您还需要(滥用)使用数据声明和整个类型系统来让他们屈服于这样的想法,这只会让事情变得更糟。
大家好Haskell粉丝们!
我所有的问题都是关于 -- OVERLOADED(?) FUNCTION -- 部分,为了完整起见,我将其余部分包括在内。
我想知道使用模式匹配来重载我的函数 order 是否有意义,就像我在下面的示例中所做的那样。
我还想知道 order 函数的第一个版本中第一个带有函数调用“checkBalance balance”的函数是否总是被执行(因为我没有为其指定模式)或从不(因为 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
我看不出该函数定义有任何问题。
函数子句按顺序尝试,所以第一个带有 checkBalance
的分支总是先被尝试,然后是下一个守卫,依此类推,如果第一个守卫的 none匹配组,则尝试下一组(O Indian {} _ _
)。
如果第一组的守卫穷尽,那么下面的其他分支就无法到达,那就说明有问题,但不详细就不好说了。
-- OVERLOADED(?) FUNCTION --
order :: (Order, CreditBalance) -> OrderStatus
order (O {}, balance)
| not (checkBalance balance ) = Declined
| ...
上面的模式将涵盖所有情况,低于它的任何东西都没有机会检查。
原因是Order
只有一个构造函数,即O
,而(O {})
匹配所有可能的参数给O
构造函数。元组的另一个成员只是一个简单的 Int
,它始终匹配。
由于模式是从上到下匹配的,并且会选择第一个匹配的模式,因此它们在代码中的定义顺序很重要。如果您将尽可能广泛的模式放在顶部,那么下面更具体的模式将永远没有机会匹配。
至于重载函数,我可以想到如何(滥用)使用模式匹配来模仿 OOP 中的函数重载,但是您还需要(滥用)使用数据声明和整个类型系统来让他们屈服于这样的想法,这只会让事情变得更糟。