Haskell/GHC: Matching multiple unary constructors with the same pattern

主宰稳场 提交于 2021-01-27 06:53:33

问题


So I was playing around with defining a TrieSet datatype (even though I know I don't need to):

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

When I got an error I've never seen before:

% ghc -c Temp.hs
Temp.hs:8:11: Parse error in pattern

So it seemed like GHC doesn't like matching multiple unary constructors with the same pattern. I did another test to make sure that was the problem:

module Temp2 where

extract :: Either String String -> String
extract (_ s) = s

Which seemed to confirm my suspicion:

% ghc -c Temp2.hs
Temp2.hs:4:9: Parse error in pattern

So my question is (in multiple parts):

  1. Am I right about why GHC doesn't like these functions?
  2. Any reason why this wouldn't be a part of the Haskell standard? After all, we can match multiple nullary constructors with the same pattern.
  3. Is there a LANGUAGE pragma I can give GHC to make it accept these?

回答1:


  1. Yes. That kind of wildcards was never supported.
  2. In my opinion, it would be much more difficult to infer a function's type if you don't know the data-constructor that was matched on. Just think about a function f (_ n) = n. What should be its type? The type-system of Haskell has no way to describe the arity of a type's constructors, so a function like f could not exist.
  3. I don't think so.



回答2:


If it makes sense to match two or more constructors with a wildcard pattern, it probably also makes sense to unify those constructors and use an additional enumerated value to distinguish between them.

For example:

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

foo :: TrieSet X -> X
foo (Node _ m) = ...

If you don't want to make this change to your existing datatype, you could instead define a helper type and a corresponding helper function, and perform the conversion before you pattern-match.

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


来源:https://stackoverflow.com/questions/7131954/haskell-ghc-matching-multiple-unary-constructors-with-the-same-pattern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!