量化类型和模式匹配问题

问题描述 投票:0回答:1

在一个连接到解析的小型库中,我最初有一个以下形式的错误类型(使用 GADT 语法):

data ParseError s e where
    -- | Error with no indication of its origin.
    Fail :: ParseError s e
    ParseError
        :: !Text                                       -- ^ Error message.
        -> !s                                          -- ^ State component.
        -> !e                                          -- ^ Error component.
        -> ParseError s e

Text
字段能够将一些信息附加到错误中,
s
字段用于捕获解析器的状态(例如源位置、偏移量等)。然而,重要的字段是
e
字段,它充当一种分类标签。通常,它将是单例类型(或者可能是围绕一些额外数据的新类型),或者是此类类型的联积。说
EndOfInputError
ValidationError
Either EndOfInputError ValidationError
等等

然后我想,为错误添加回溯不是很好吗?鉴于回溯可能包含不同类型

e
的错误,该字段必须是量化类型,因此我们最终得到:

data ParseError s e where
    -- | Error with no indication of its origin.
    Fail :: ParseError s e
    ParseError
        :: !Text                               -- ^ Error message.
        -> (forall d . Maybe (ParseError s d)) -- ^ Error backtrace.
        -> !s                                  -- ^ State component.
        -> !e                                  -- ^ Error component.
        -> ParseError s e

在实践中,量化字段是不同

ParseError
e
列表,因此对于一般处理,我有:

backtrace :: (forall d . Text -> s -> d -> a) -> ParseError s e -> [a]
backtrace f  = go
    where
        go Fail = []
        go (ParseError xs Nothing s e)  = [f xs s e]
        go (ParseError xs (Just b) s e) = f xs s e : backtrace f b

不幸的是,阴谋集团的错误是:

src/Bins/Types/ParseError.hs:38:9: error: [GHC-62161] [-Wincomplete-patterns, Werror=incomplete-patterns]
    Pattern match(es) are non-exhaustive
    In an equation for ‘go’:
        Patterns of type ‘ParseError s e’ not matched: ParseError _ _ _ _
   |
38 |         go Fail = []
   |         ^^^^^^^^^^^^...

我不明白为什么这会给我一个关于非详尽模式的错误。在我未经训练的眼睛看来,这些方程涵盖了所有可能的情况,因此我显然错过了有关量化类型如何与模式匹配交互的信息。谁能给我解释一下吗?

以防万一,这很重要:语言 GHC2021 和 GHC v9.10.1。需要更多详细信息,请询问。

haskell
1个回答
0
投票

你所写的内容是,如果我有一个值

ParseError desc stack state err
,那么无论我选择哪种类型的错误,
stack
都可以向我提供包含该类型的解析错误。我怀疑您的意图是构建
ParseError
值的人可以选择存储在堆栈中的类型。为了表达这一点,你可以这样写:

ParseError :: forall d.
       !Text                               -- ^ Error message.
    -> Maybe (ParseError s d)              -- ^ Error backtrace.
    -> !s                                  -- ^ State component.
    -> !e                                  -- ^ Error component.
    -> ParseError s e

您几乎肯定需要对

d
进行某种类型类约束——否则您无法使用该值执行任何操作!

ParseError :: forall d. Exception d
    => !Text                               -- ^ Error message.
    -> Maybe (ParseError s d)              -- ^ Error backtrace.
    -> !s                                  -- ^ State component.
    -> !e                                  -- ^ Error component.
    -> ParseError s e

为了保持一致性,我很想将存在的一层向上移动到堆栈中。

data ParseError s where
    -- | Error with no indication of its origin.
    Fail :: ParseError s
    ParseError :: forall e. Exception e
        => !Text                               -- ^ Error message.
        -> Maybe (ParseError s)                -- ^ Error backtrace.
        -> !s                                  -- ^ State component.
        -> !e                                  -- ^ Error component.
        -> ParseError s
© www.soinside.com 2019 - 2024. All rights reserved.