我很不情愿地提出这种问题,但我已经快要放弃了。我正在编写一个增量解析器,但是由于某些原因,无法理解如何为其实现函数对象实例。以下是代码转储:
输入数据类型
输入是由解析器生成的数据类型,用于协程。它包含当前列表中协程正在操作的输入字符及行末条件。
data Input a = S [a] Bool deriving (Show)
instance Functor Input where
fmap g (S as x) = S (g <$> as) x
输出数据类型
输出数据类型是协程传递给解析器的数据类型。它可以是失败的消息、完成的 [b] 或部分的 ([a] -> Output a b),其中 [a] 是当前传递回解析器的缓冲区。
data Output a b = Fail String | Done [b] | Partial ([a] -> Output a b)
instance Functor (Output a) where
fmap _ (Fail s) = Fail s
fmap g (Done bs) = Done $ g <$> bs
fmap g (Partial f) = Partial $ \as -> g <$> f as
解析器
解析器接收 [a] 并将其转换为缓冲区 [a] 以供协程使用,协程会返回输出 Output a b。
data ParserI a b = PP { runPi :: [a] -> (Input a -> Output a b) -> Output a b }
函数对象实现
看起来我们需要做的就是将函数g映射(fmap)到协程上,就像下面这样:
instance Functor (ParserI a) where
fmap g p = PP $ \as k -> runPi p as (\xs -> fmap g $ k xs)
但它无法进行类型检查:
Couldn't match type `a1' with `b'
`a1' is a rigid type variable bound by
the type signature for
fmap :: (a1 -> b) -> ParserI a a1 -> ParserI a b
at Tests.hs:723:9
`b' is a rigid type variable bound by
the type signature for
fmap :: (a1 -> b) -> ParserI a a1 -> ParserI a b
at Tests.hs:723:9
Expected type: ParserI a b
Actual type: ParserI a a1
fmap g p = PP $ \as k -> runPi p as (\xs -> fmap g $ k xs)
<- 那个最后的as
应该是想写成xs
,对吧? - Daniel FischerPP
构造函数的第二个参数是一个函数,或者你可以以其他方式存储这些信息?显然这就是问题所在。 - AndrewC