如何将模式绑定到数据结构中的特定项?

时间:2015-04-20 16:32:54

标签: haskell

考虑下面的简单数据结构(我学习如何使用attoparsec)。我没有自动导出节目,而是为它创建了一个实例。但是,如果DateDefinition中项目的顺序发生了变化,那么该实例将立即中断(返回错误的答案)(例如,我将dayOfMonth放在monthOfYear之前)。 必须有一种方法可以将模式中的每个条目与数据结构中的每个条目相关联,这样它就不会受到项目顺序变化的影响。但是怎么样?我尝试使用实际的名称,但毫不奇怪,这不起作用,只是导致关于阴影现有绑定的警告。

data DateDefinition = DateDefinition
            {
                 monthOfYear :: Months,
                 dayOfMonth :: Int,
                 hourOfDay :: Int,
                 minuteOfHour :: Int,
                 secondOfMinute :: Int
            }

instance Show DateDefinition where
   show (DateDefinition m d _ _ _) = show m  ++  " " ++ show d

3 个答案:

答案 0 :(得分:5)

您可以直接使用字段访问者;这是最简单的方法:

instance Show DateDefinition where
    show dd = show (monthOfYear dd) ++ " " ++ show (dayOfMonth dd)

或者,您可以使用RecordWildCards扩展程序:

instance Show DateDefinition where
    show DateDefinition{..} = show monthOfYear ++ " " ++ show dayOfMonth

如果您从未打算摆脱这些领域,那就太好了。如果你想在不破坏任何内容的情况下更改内部结构,那么第一个实现(as pointed out by rampion)可能是最安全的。只要你不导出构造函数,你总是可以将这些字段变成普通的函数而不需要知道。

答案 1 :(得分:4)

可以使用'记录双关语'用于与NamedFieldPuns扩展名匹配的简洁记录:

instance Show DateDefinition where
    show (DateDefinition {monthOfYear, dayOfMonth}) =
        show monthOfYear ++ " " ++ show dayOfMonth

您也可以在没有扩展名的情况下以类似方式进行模式匹配:

instance Show DateDefinition where
    show (DateDefinition {monthOfYear = month, dayOfMonth = day}) =
        show month ++ " " ++ show day

如果你真的不想进行模式匹配,你可以通过使用提取值的函数来做更脏的方法:

instance Show DateDefinition where
    show date =
        show (monthOfYear date) ++ " " ++ show (dayOfMonth date)

这肯定比其他人更为温和。


也可能值得将您的数据类型重命名为Date,并更改功能以保持代码简洁,因为您当前使用的名称并不是很好:

data Date = Date 
           { month     :: Months
           , day       :: Int
           , hour      :: Int
           , minute    :: Int
           , second    :: Int
           }

答案 2 :(得分:3)

您可以使用字段名称进行模式匹配:

instance Show DateDefinition where
   show (DateDefinition { monthOfYear = m, dayOfMonth = d }) 
     = show m ++  " " ++ show d

或者,如果您担心将来完全摆脱这些字段,可以使用ViewPatterns

instance Show DateDefinition where
   show (monthOfYear -> m)@(dayOfMonth -> d) = show m ++  " " ++ show d

(不,不能用@执行此操作。)