有一些类型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
如何改写?
答案 0 :(得分:4)
范围是整个表达式(包括where子句中的定义),除了模式中的变量总是定义一个新的变量绑定。
您应该在内部绑定中使用不同的变量名称,而不是重复使用相同的名称。
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
重用变量名以使其隐藏外部作用域中的变量称为 shadowing 。如果您使用-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
但是如果你想使用它,你就不能避免为模式的一部分命名,即使只是将它与其他模式进行比较。
答案 1 :(得分:0)
模式匹配的形式如下:构造函数binding1 binding2 ...其中绑定只是(并且只有!)允许为使用值命名的一部分是右侧。这就是你在左边的价值时所能做的一切。 在您的第一个示例中,您似乎希望通过在绑定中引入绑定名称来约束匹配,但这不会以这种方式工作。看看你想要什么。