使用存在量化来键入解析器的签名

时间:2014-09-12 13:26:39

标签: parsing haskell types existential-type

一开始我有一个解析器的简单类型:

data Parser a = Parser ([Token] -> Either String (a, [Token]))


我在左侧使用Either作为错误消息,在右侧使用其余标记的解析表达式。

此函数“解包”解析器函数。

parse :: Parser a -> [Token] -> Either String (a, [Token])
parse (Parser p) = p

我的目标是使Parser更加通用,它不仅将令牌作为输入。所以我使用了ExistentialQuantification编译指示并将其更改为:

data Parser a = forall b. ([b] -> Either String (a, [b]))


我想知道的是:该功能现在有什么类型的“解析”?


我无法弄明白,也无法推断出来。 GHCi给出了这个错误:

Couldn't match type `t' with `[b] -> Either String (t1, [b])'
  `t' is a rigid type variable bound by
    the inferred type of parse :: Parser t1 -> t
    at ParserCombinator.hs:9:1
In the expression: p
In an equation for `parse': parse (Parser p) = p

感谢您的帮助。



编辑: 非常感谢您的回答。

我之所以希望类型看起来像“Parser a”,是因为我在其他解析库中看到过这种情况,例如在parsec中。 但我现在看到,这只是将字符串作为输入的解析器的简写。

使用“data Parser b a”是有意义的。这也是我之前尝试过的,但后来我的解析器monad实例中出现了一个奇怪的错误,因为我写了数据Parser而不是:

import Control.Monad.Error

data Parser a b = Parser ([b] -> Either String (a, [b]))
parse (Parser p) = p

instance Monad (Parser x) where
    p >>= f = Parser (\tokens -> do
        (parsed, rest) <- parse p tokens 
        parse (f parsed) rest)
    return a = Parser (\ts -> Right (a, ts))
    fail b     = Parser (\_ -> Left b)

它给出了这个错误:

ParserCombinator.hs:12:18:
    Couldn't match type `x' with `b'
      `x' is a rigid type variable bound by
          the instance declaration at ParserCombinator.hs:9:24
      `b' is a rigid type variable bound by
          the type signature for
            >>= :: Parser x a -> (a -> Parser x b) -> Parser x b
          at ParserCombinator.hs:10:5
    Expected type: a
      Actual type: x
    In the first argument of `f', namely `parsed'
    In the first argument of `parse', namely `(f parsed)'
    In a stmt of a 'do' block: parse (f parsed) rest

ParserCombinator.hs:12:26:
    Couldn't match type `a' with `b'
      `a' is a rigid type variable bound by
          the type signature for
            >>= :: Parser x a -> (a -> Parser x b) -> Parser x b
          at ParserCombinator.hs:10:5
      `b' is a rigid type variable bound by
          the type signature for
            >>= :: Parser x a -> (a -> Parser x b) -> Parser x b
          at ParserCombinator.hs:10:5
    Expected type: [b]
      Actual type: [a]
    In the second argument of `parse', namely `rest'
    In a stmt of a 'do' block: parse (f parsed) rest

ParserCombinator.hs:13:38:
    Couldn't match type `a' with `x'
      `a' is a rigid type variable bound by
          the type signature for return :: a -> Parser x a
          at ParserCombinator.hs:13:5
      `x' is a rigid type variable bound by
          the instance declaration at ParserCombinator.hs:9:24
    In the expression: a
    In the first argument of `Right', namely `(a, ts)'
    In the expression: Right (a, ts)

如果使用Parser b a而不是Parser a b,它为什么会起作用?为什么我需要在Parser x中使用这个x?它包含什么? 如果您能为另一个使用此变量的monad实例提供示例,那将是很好的。

1 个答案:

答案 0 :(得分:9)

你的意思是

data Parser a = forall b. Parser ([b] -> Either String (a, [b]))

如果你用更严格的GADT符号写出存在主义,这实际意味着什么变得更清楚:

data Parser a where
  Parser :: forall b. ([b] -> Either String (a, [b])) -> Parser a

即。构造函数Parser是一个普遍量化的函数,它使用([b] -> ...解析器,但始终返回一个Parser a,它不知道要在其中使用哪个特定的b。因此,这基本上是无用的:如果您不知道实际应该是什么类型,则无法提供b令牌列表!

使其具体化:parse将与Parser相反;交换量子因此它是一个存在的(duh)函数

parse :: exists b . Parser a -> ([b] -> Either String (a, [b]))

现在,Haskell中不存在这样的类型,但它等同于通用的参数:

parse :: Parser a -> ((forall b . [b]) -> Either String (a, exists b . [b]))

此时很明显你不能以任何有意义的方式使用它:forall b. [b]的唯一居民是[]undefined(正如Tikhon Jelvis评论的那样,{{ 1}},[undefined][undefined, undefined]等。)。


我不确定你打算用这种类型做什么,但存在主义绝对不是正确的做法。可能你应该做

[undefined, undefined, undefined]