Haskell 如何组合case语句模式
我试图在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 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 -> …
…