有一些类型Record
:
type Day = Integer
type Description = String
type Name = String
type PhoneNumber = String
type Year = Integer
data Month = January | February | March | April | May | June | July
| August | September | October | November | December
deriving (Eq, Ord, Enum, Show)
data Birthday = Birthday Month Day
deriving (Eq, Show)
data DatingDate = DatingDate Year Month Day
deriving (Eq, Show)
data Record = BirthdayRecord Name Birthday
| PhoneRecord Name PhoneNumber
| DatingRecord DatingDate Description
deriving (Eq, Show)
以及按日期过滤这些记录的函数:
getAssignment :: (Year, Month, Day) -> [Record] -> [Record]
getAssignment (year, month, day) = filter matchDate
where matchDate (BirthdayRecord _ (Birthday month day)) = True
matchDate (DatingRecord (DatingDate year month day) _) = True
matchDate _ = False
getAssignment
的定义由于错误而不正确:
warning: Defined but not used: `year'
事实上,year
对我来说有点意外。在 getAssignment
的模式匹配部分和year
在 matchDate
的模式匹配部分不一样。
那么,year
的范围边界在哪里?变量开始和结束?发生这种情况是因为 where
部分?
顺便说一句,这个错误可以通过大量使用 (year, month, day)
来避免。变量。
getAssignment' :: (Year, Month, Day) -> [Record] -> [Record]
getAssignment' date = filter (matchDate date)
where matchDate (_, m, d) (BirthdayRecord _ (Birthday month day)) =
month == m && day == d
matchDate (y, m, d) (DatingRecord (DatingDate year month day) _) =
year == y && month == m && day == d
matchDate _ _ = False
如何重写?
最佳答案
范围是整个表达式(包括 where 子句中的定义),但模式中的变量始终定义新的变量绑定(bind)。
您应该在内部绑定(bind)中使用不同的变量名称,而不是重复使用相同的名称。
getAssignment :: (Year, Month, Day) -> [Record] -> [Record]
getAssignment (year, month, day) = filter matchDate
where matchDate (BirthdayRecord _ (Birthday month' day'))
= month == month' && day == day'
matchDate (DatingRecord (DatingDate year' month' day') _)
= year == year' && month == month' && day == day'
matchDate _ = False
重用变量名以隐藏外部作用域中的变量称为遮蔽。如果您使用 -Wall
(或 -fwarn-name-shadowing
仅启用此警告),GHC 应该在您执行此操作时发出警告。
编辑:对于您的特定函数,这可能是更清晰的编写方式:
getAssignment :: (Year, Month, Day) -> [Record] -> [Record]
getAssignment (year, month, day) = filter matchDate
where matchDate (BirthdayRecord _ birthday) = birthday == Birthday month day
matchDate (DatingRecord date _) = date == DatingDate year month day
matchDate _ = False
但是,如果您想使用模式的一部分,就无法避免为它命名,即使只是将其与其他内容进行比较。
关于haskell - 模式匹配变量的范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10057659/