2015-02-06 66 views
3

多态数据,假设我们有一个名为东西定义的数据:匹配在Haskell

data Stuff = Stuff1 Int 
      | Stuff2 Int 
      | Stuff3 Int 

sumStuff :: [Stuff] -> Int 
sumStuff [] = 0 
sumStuff ((Stuff1 x):xs) = x + sumStuff xs 
sumStuff ((Stuff2 x):xs) = x + sumStuff xs 
sumStuff ((Stuff3 x):xs) = x + sumStuff xs 

sumStuff' :: [Stuff] -> Int 
sumStuff' [] = 0 
sumStuff' ((_ x):xs) = x+sumStuff xs 

如何我可以匹配所有类型的无图案像在sumStuff”错误的定义相匹配?

预先感谢您!

回答

13

你可以采取与您的数据结构不同的方法,如果它是作为同质作为例子:

data StuffType = Stuff1 | Stuff2 | Stuff3 deriving (Eq, Show) 

data Stuff a = Stuff StuffType a deriving (Eq, Show) 

extractStuff :: Stuff a -> a 
extractStuff (Stuff _ a) = a 

sumStuff :: Stuff Int -> Int 
sumStuff = sum . map extractStuff 

我还送包含在Stuff多态的价值,如果你想存储String S或甚至更多Stuff在他们中。这种方法允许您在需要时在StuffType上进行模式匹配,但是当您不需要时可以使用单个模式案例。

你也可以使用记录,以避免模式定义这个完全匹配:

data Stuff a = Stuff { stuffType :: StuffType, extractStuff :: a } deriving (Eq, Show) 

sumStuff将具有相同的定义,但你不会需要手动定义extractStuff

+0

这是比其他答案更懒。如果每个'Stuff'都含有'exactStuff',则在使用'exactStuff'之前,不需要确定它是否为'Stuff1','Stuff2'或'Stuff3'。 – Cirdec 2015-02-06 22:58:27

1

你真的不能。你能做的最好是写这样的:

toInt :: Stuff -> Int 
toInt (Stuff1 x) = x 
toInt (Stuff2 x) = x 
toInt (Stuff3 x) = x 

sumStuff :: [Stuff] -> Int 
sumStuff [] = 0 
sumStuff (x:xs) = toInt x + sumStuff xs 

基本上你隐藏了背后的toInt功能相匹配的模式。

4

我认为您正在寻找Lenses它们允许您查看数据类型并查看或更改包含的值,在这种情况下,它们可以简化模式匹配。 This是开始了解它们的好地方。

用镜头书写这可能看起来像:

data Stuff = Stuff1 { _stuff :: Int } | 
      Stuff2 { _stuff :: Int } | 
      Stuff3 { _stuff :: Int } 
makeLenses ''Stuff 

sumStuff []  = 0 
sumStuff (x:xs) = x ^. stuff + sumStuff xs 

在这种情况下,镜头可能是矫枉过正,因为你可以只使用记录语法。即

data Stuff = Stuff1 {stuff :: Int } | 
      Stuff2 {stuff :: Int } | 
      Stuff3 {stuff :: Int } 

sumStuff []  = 0 
sumStuff (x:xs) = stuff x + sumStuff xs 

sumStuff = foldr ((+) . stuff) 0

希望这有助于。