1

为了好玩,我正在构建一个解析器库。在这个库中,我有一个Parser数据类型:

data Parser e a = Parser (String -> Either e (a, String))

我可以定义FunctorApplicative的实例Parser,但我认为我不能在Alternative不限制解析器可以返回的“错误”类型或“值”类型的情况下创建实例。最初,这使我Applicative为错误类型是String消息时创建了一个实例,但我意识到我应该能够将此约束释放到任何具有Alternative(或者可能Monoid是?)实例的消息数据类型。考虑到这一点,我写了这个:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
instance Alternative e => Alternative (Parser e)
  where
    empty = Parser $ \s -> Left empty
    (<|>) (Parser p1) (Parser p2) = Parser $ \s -> tryParser s p2 $ p1 s
      where
        tryParser s p2 (Left _ ) =  p2 s
        tryParser _ _ x          = x

不幸的是,这无法编译。当我将它加载到 ghci 中时,我收到以下错误消息:

Parsertest.hs:31:47:
    Expecting one more argument to `e'
    In the instance declaration for `Alternative (Parser e)'
Failed, modules loaded: none.

当我在网上搜索时,这似乎是解决方案,但它对我不起作用。我错过了什么?

4

1 回答 1

6

问题在于Alternative类型构造函数类型* -> *,所以如果你说

instance Alternative e => ....

然后e必须是类型构造函数,而不是类型。所以e可能是[]orMaybe或什么,但不是Int

Alternative的运算符是<|>具有类型的Alternative e => e a -> e a -> e a。这迫使e接受一个参数来创建一个类型,就像Maybe必须接受一个参数一样,例如Maybe Int.

使用Monoid代替Alternative,因为它是类型类而不是构造函数类。它的运算符mappend具有Monoid e => e -> e -> e您想要组合错误的类型。

于 2013-08-13T23:05:01.447 回答