Haskell/GHC:匹配具有相同模式的多个一元构造函数

ram*_*ion 4 constructor haskell pattern-matching ghc

所以我正在玩定义TrieSet数据类型(即使我知道我不需要):

module Temp where

import Data.Map

data TrieSet a = Nonterminal (Data.Map a (TrieSet a)) | Terminal (Data.Map a (TrieSet a))

insert :: Ord a => [a] -> TrieSet a -> TrieSet a
insert [] (_ m) = Terminal m
insert (a:as) (c m) = c $ insertWith (insert as . flip const) a (insert as $ Nonterminal empty) m
Run Code Online (Sandbox Code Playgroud)

当我收到一个我从未见过的错误时:

% ghc -c Temp.hs
Temp.hs:8:11: Parse error in pattern
Run Code Online (Sandbox Code Playgroud)

因此,似乎GHC不喜欢使用相同模式匹配多个一元构造函数.我做了另一个测试,以确保这是问题:

module Temp2 where

extract :: Either String String -> String
extract (_ s) = s
Run Code Online (Sandbox Code Playgroud)

这似乎证实了我的怀疑:

% ghc -c Temp2.hs
Temp2.hs:4:9: Parse error in pattern
Run Code Online (Sandbox Code Playgroud)

所以我的问题是(分多部分):

  1. 我对GHC不喜欢这些功能的原因是肯定的吗?
  2. 有什么理由不将其作为Haskell标准的一部分?毕竟,我们可以匹配具有相同模式的多个nullary构造函数.
  3. 是否有一个LANGUAGE编译指示我可以给GHC让它接受这些?

fuz*_*fuz 9

  1. 是.从来没有支持过这种通配符.
  2. 在我看来,如果你不知道匹配的数据构造函数,推断一个函数的类型将会困难得多.想想一个功能f (_ n) = n.应该是什么类型的?Haskell的类型系统无法描述类型构造函数的arity,因此函数f不可能存在.
  3. 我不这么认为.


Stu*_*ook 8

如果将两个或多个构造函数与通配符模式匹配是有意义的,那么统一这些构造函数并使用额外的枚举值来区分它们可能也是有意义的.

例如:

data Terminality = Terminal | Nonterminal
data TrieSet a = Node Terminality (Data.Map a (TrieSet a))

foo :: TrieSet X -> X
foo (Node _ m) = ...
Run Code Online (Sandbox Code Playgroud)

如果您不想对现有数据类型进行此更改,则可以改为定义帮助程序类型和相应的帮助程序函数,并在模式匹配之前执行转换.

data TreeSetView a = Node Terminality (Data.Map a (TrieSet a))

view :: TrieSet a => TreeSetView a
view (Terminal    m) = TreeSetView TerminalityTerminal    m
view (Nonterminal m) = TreeSetView TerminalityNonterminal m
Run Code Online (Sandbox Code Playgroud)