【发布时间】:2013-07-18 21:58:23
【问题描述】:
我真的很讨厌问这种问题,但我已经无能为力了。我正在编写一个增量解析器,但由于某种原因,我无法弄清楚如何为其实现仿函数实例。这是代码转储:
输入数据类型
输入是解析器向协程产生的数据类型。它包含协程正在操作的输入字符的当前列表和行尾条件
data Input a = S [a] Bool deriving (Show)
instance Functor Input where
fmap g (S as x) = S (g <$> as) x
输出数据类型
输出是协程向 Parser 产生的数据类型。它可以是 Failed 消息、Done [b] 或 Partial ([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] 给协程,协程返回输出 a b
data ParserI a b = PP { runPi :: [a] -> (Input a -> Output a b) -> Output a b }
函子实现
似乎我所要做的就是将函数 g 映射到协程上,如下所示:
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
【问题讨论】:
-
ParserI不是函子。不存在实例。 -
Oh X( 我可以请你解释一下为什么吗?我该如何重组它使其成为一个仿函数?例如在 Attoparsec.Incremental (已弃用)中,协程的类型类似于 (c -> 输入 a -> 输出 a b),但我不知道 c 是干什么用的
-
fmap g p = PP $ \as k -> runPi p as (\xs -> fmap g $ k as)as 本来应该是一个xs,不是吗? -
对。现在它是有道理的(错误消息)。问题是您需要将
Input a -> Output a b作为第二个参数传递给runPi p。但是你所拥有的k是Input a -> Output a c(当g的类型是b -> c时)。您需要某种方法将Input a -> Output a c转换为Input a -> Output a b。但是您无法从c创建b。类型变量b出现在错误的位置,使ParserI成为Functor。这就是 Philip JF 所说的。 -
您是否确实需要
PP构造函数的第二个参数作为函数,或者您可以以其他方式存储该信息吗?这显然是问题所在。