haskell - 模式匹配变量的范围

标签 haskell pattern-matching scope

有一些类型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 的模式匹配部分和yearmatchDate 的模式匹配部分不一样。

那么,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/

相关文章:

regex - 如何对多行字符串进行模式匹配?

c++ - 在 C 与 C++ 中使用函数调用初始化全局变量

javascript - 如何从嵌套对象文字访问外部成员?

Haskell 自定义数据类型、实例数和冗余

haskell - 如何使用 Haskell 库 Linear 缩放向量?

haskell - 如何实现 mapAccumM?

Haskell 无法将预期类型 float 与实际类型 'a' 匹配

c# - 包含的集合数量的简明解决方案

scala - 在scala中对一系列值进行模式匹配

我可以存储指向 __PRETTY_FUNCTION__ 的指针以供以后使用,还是需要立即复制该字符串?