2012-04-07 123 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 ...其中綁定僅僅(並且僅!)允許爲使用情況命名一部分值是右側。當你在左邊添加值時,你可以做的就是這些。 在你的第一個例子中,你似乎想通過在綁定中引入綁定名稱來限制匹配,但這不會那樣工作。看到你想要的衛兵。