假设我们有一个名为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中的错误定义?
提前谢谢!
答案 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
函数后面的模式匹配。