在Haskell中匹配多态数据

时间:2015-02-06 20:50:07

标签: 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中的错误定义?

提前谢谢!

3 个答案:

答案 0 :(得分: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甚至更多Stuff。这种方法允许您在需要时对StuffType进行模式匹配,但是当您不需要时,可以使用单个模式案例。

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

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

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

答案 1 :(得分: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

希望这有帮助。

答案 2 :(得分: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函数后面的模式匹配。