Haskell 如何组合case语句模式

Haskell 如何组合case语句模式,haskell,ghc,Haskell,Ghc,我试图在case语句中匹配许多不同的构造函数。为简单起见,假设在一半情况下我们做相同的事情,而在另一半情况下我们做其他事情。即使我将逻辑分解为另一个函数,我仍然必须编写: case x of C1 -> foo x C2 -> foo x ... C10 -> bar x C11 -> bar x ... 是否有某种方法使case语句的行为更像C中的switch语句(即使用fallthrough),或者使我可以同时匹配许多模式中的一种,例如: c

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

case x of
  C1 -> foo x
  C2 -> foo x
  ...
  C10 -> bar x
  C11 -> bar x
  ...
是否有某种方法使case语句的行为更像C中的
switch
语句(即使用fallthrough),或者使我可以同时匹配许多模式中的一种,例如:

case x of
  C1, C2, C3 -> foo x
  C10, C11, C12 -> bar x
或者用另一种方法来解决这个问题?

这些被称为析取模式,Haskell没有。然而,有一些典型的解决办法。如果您的类型是枚举,则可以使用相等,例如使用
大小写
表达式、保护或
多路If

exampleCase cond = case cond of
  c
    | 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 -> …
  …
{-#语言
LambdaCase,
同义词,
视图模式#-}
--编写一个函数来匹配每个属性。
美食家:T->可能是X
fooish=\case
c1x->Just x
C2 x->Just x
…
C10->无
C11->无
…
--可以在此处使用通配符“\u1”;我不喜欢,
--在类型更改时要求更新案例。
巴里什:T->Bool
巴里什=\case
C1{}->False
C2{}->False
…
C10->True
C11->True
…
--创建与这些属性匹配的同义词。
--(这些恰好是单向的。)
模式Fooish::T->Foo
图案美轮美奂(仅x)
模式Barrish::T->Bar
模式(正确)
--如果它们涵盖所有情况,请告诉编译器。
--这有助于使用“-Wall”生成有用的警告。
{-#完全是美食家,巴里什}
--像正常模式一样使用它们。
示例同义词x=的案例x
美食家x->…
…
巴里什->…
…

我将
x
作为
foo
bar
的参数,因为这是我的用例。它还防止了一个丑陋但正确的答案,即使用单独的分区函数将等效构造函数合并到一个常见的情况中(如
C1->C1,C2->C1,C3->C1
,然后只在
C1
)上进行匹配。请注意,如果有人感兴趣,当前有一个休眠的方法来引入“或模式”。。。
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
{-# 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 -> …
  …