2012-04-07 75 views
1

有一些类型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模式匹配部分getAssignmentyear模式匹配部分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 

怎样才可以改写?

回答

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 

重用一个变量名,使得其隐藏从外部作用域的变量被称为遮蔽。如果您使用-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 

但是如果你想使用它,你不能避免给人一个名称模式的一部分,即使只是将它与其他东西进行比较。

+0

有什么办法可以抑制'month'和'month''变量吗? – 2012-04-07 20:02:29

+0

对不起,我不明白你的评论。你能否提供你要求的更多细节? – dave4420 2012-04-07 20:07:02

+0

当我看到'f x = x == y'的定义时,我想重写它,因为'f y == True',因为'x'变量的多余使用。在这种情况下,我想用同样的技巧来摆脱“年”,“月”和“日”变量。 – 2012-04-07 20:18:05

0

模式匹配的形式如下:构造函数binding1 binding2 ...其中绑定仅仅(并且仅!)允许为使用情况命名一部分值是右侧。当你在左边添加值时,你可以做的就是这些。 在你的第一个例子中,你似乎想通过在绑定中引入绑定名称来限制匹配,但这不会那样工作。看到你想要的卫兵。