匹配 Haskell 中的多态数据

Matching polymorphic data in Haskell

假设我们定义了一个名为 Stuff 的数据:

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 中的错误定义一样?

提前致谢!

你真的做不到。你能做的最好的就是写这样的东西:

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 函数后面。

我认为您正在寻找 Lenses They allow you to look into data types and view or change the contained value(s), and in cases such as this, they can simplify pattern matching. This 是开始了解它们的好地方。

用 Lenses 写这个看起来像:

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

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

在这种情况下,Lenses 可能有点矫枉过正,因为您可以只使用记录语法。即

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

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

sumStuff = foldr ((+) . stuff) 0

希望这对您有所帮助。

如果数据结构与您的示例一样同质,您可以对数据结构采取不同的方法:

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 甚至更多 Stuff。这种方法允许您在需要时在 StuffType 上进行模式匹配,但在不需要时坚持使用单一模式。

您也可以使用记录来定义它,以避免完全匹配模式:

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

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