PureScript嵌套穷举模式匹配的静态检查可行方案问询
Haskell编译器无法自动推断other不可能是Bar构造器,因此会判定后续的case语句非穷举。要实现静态可检查的穷举匹配,可通过以下几种方式:
方案1:拆分类型(最直观)
将Foo拆分为包含Bar的主类型,以及仅包含Quux、Baz的子类型,让编译器明确子类型的构造器范围:
data Foo = Bar Int | NonBar NonBarFoo data NonBarFoo = Quux Int | Baz Int f :: Foo -> Int f (Bar n) = n f (NonBar nb) = case nb of Quux n -> 2 * n Baz n -> 3 * n g :: Foo -> Int g foo = case foo of Bar n -> n NonBar nb -> case nb of Quux n -> 2 * n Baz n -> 3 * n
处理NonBarFoo的case语句会被编译器判定为完全穷举,因为NonBarFoo仅包含Quux和Baz两个构造器,不存在其他分支。
方案2:使用GHC扩展的COMPLETE编译指示(保留原类型)
如果不想拆分类型,可借助GHC的PatternSynonyms和ViewPatterns扩展,手动告知编译器已排除Bar构造器:
{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ViewPatterns #-} data Foo = Bar Int | Quux Int | Baz Int -- 定义视图模式,匹配非Bar的构造器 pattern NonBar :: Foo -> Foo pattern NonBar x <- (filterBar -> Just x) where NonBar x = x filterBar :: Foo -> Maybe Foo filterBar (Bar _) = Nothing filterBar x = Just x -- 告知编译器:匹配NonBar视图返回的Foo时,Quux和Baz是穷举的 {-# COMPLETE Quux, Baz #-} f :: Foo -> Int f (Bar n) = n f (NonBar other) = case other of Quux n -> 2 * n Baz n -> 3 * n
COMPLETE编译指示会让GHC确认,此时无需再处理Bar分支,从而判定case语句穷举。
方案3:合并模式匹配(最简洁)
如果不需要拆分逻辑,直接将所有构造器放在同一个case中,天然满足静态穷举检查:
data Foo = Bar Int | Quux Int | Baz Int f :: Foo -> Int f foo = case foo of Bar n -> n Quux n -> 2 * n Baz n -> 3 * n g :: Foo -> Int g = \case Bar n -> n Quux n -> 2 * n Baz n -> 3 * n
内容的提问来源于stack exchange,提问作者Brennan Vincent
相关产品推荐
相关产品推荐

