如何组合 case 语句模式[重复]

问题描述 投票:0回答:1

我试图在 case 语句中匹配许多不同的构造函数。为了简单起见,假设在一半的情况下我们做同样的事情,而在另一半的情况下我们做其他的事情。即使我将逻辑分解到另一个函数中,我仍然必须写:

case x of
  C1 -> foo x
  C2 -> foo x
  ...
  C10 -> bar x
  C11 -> bar x
  ...

是否有某种方法可以使 case 语句的行为更像 C 中的

switch
语句(即失败),或者以便我可以一次匹配多种模式之一,例如:

case x of
  C1, C2, C3 -> foo x
  C10, C11, C12 -> bar x

或者也许有另一种方法来清理这个问题?

haskell ghc
1个回答
24
投票

这些被称为“析取模式”,Haskell 没有它们。 (OCaml 和 F# 可以。)但是,有一些典型的解决方法。如果您的类型是枚举,则可以使用相等性,例如使用 elem、使用

case
表达式、守卫或
MultiWayIf
:
exampleCase cond = case cond of
  c
    | c `elem` [C1, C2, C3] -> foo
    | c `elem` [C10, C11, C12] -> bar
    | otherwise -> baz

exampleGuards c
  | c `elem` [C1, C2, C3] = foo
  | c `elem` [C10, C11, C12] = bar
  | otherwise = baz
exampleIf c
  = additionalProcessing $ if
    | c `elem` [C1, C2, C3] -> foo
    | c `elem` [C10, C11, C12] -> bar
    | otherwise -> baz
当然,如果 
foo

bar
是长表达式,由于懒惰,您可以简单地将它们分解到局部定义中,因此您只需重复名称和需要作为参数的任何模式变量:
exampleWhere cond = case cond of
  C1 x -> foo x
  C2 y -> foo y
  …
  C10 -> bar
  C11 -> bar
  …
  where
    foo x = something long (involving x, presumably)
    bar = if you please then something else quite long

如果您经常以这种方式将构造函数分组在一起,则可以使用 
PatternSynonyms

语言选项(与

ViewPatterns
结合使用特别有用)来创建自己的模式来匹配此类组:
{-# Language
    LambdaCase,
    PatternSynonyms,
    ViewPatterns #-}

-- Write one function to match each property.

fooish :: T -> Maybe X
fooish = \ case
  C1 x -> Just x
  C2 x -> Just x
  …
  C10 -> Nothing
  C11 -> Nothing
  …
  -- May use a wildcard ‘_’ here; I prefer not to,
  -- to require updating cases when a type changes.

barrish :: T -> Bool
barrish = \ case
  C1{} -> False
  C2{} -> False
  …
  C10 -> True
  C11 -> True
  …

-- Create synonyms for matching those properties.
-- (These happen to be unidirectional only.)

pattern Fooish :: T -> Foo
pattern Fooish x <- (fooish -> Just x)

pattern Barrish :: T -> Bar
pattern Barrish <- (barrish -> True)

-- If they cover all cases, tell the compiler so.
-- This helps produce useful warnings with ‘-Wall’.

{-# Complete Fooish, Barrish #-}

-- Use them just like normal patterns.

exampleSynonyms x = case x of
  Fooish x -> …
  …
  Barrish -> …
  …

	
© www.soinside.com 2019 - 2024. All rights reserved.