tl;dr : 您想要这个表达式 :
betaLine = string "BETA " *> (BetaPair <$> p_int <*> p_int <*> p_int <*> p_int <*> p_direction <*> p_exposure) <* eol
阅读 下面的为什么 。
再次,这在一定程度上是一个先决问题。您现在的行是做什么的 :
string "BETA " *> p_int <*> p_int ...
...是它创造了像这样的解剖师:
(string "BETA " *> p_int) <*> (p_int) ...
这不是主要问题,但事实上,如果其余的剖析器正确无误,上面的语义错误的剖析器仍会产生正确的结果。 然而,正如你说的,你对 是如何运作的略有误解。 它的签名是:
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
正如您可以看到的那样, 函数应该将一个函数以配给符包包成为第一个参数, 然后它会使用第二个参数中的配给符包包的值来应用 < / 强 。 当您在函数开始的时候将 < code> p_int code > 作为第一个参数时, 它是一个 < code > Parker Int code > 而不是一个 < code> Parkerer (a- gt;b) code >, 所以类型不会检查 。
事实上,他们无法输入目标是否是您用推理表达的目标; 您希望 < code> beetalLine code> 和 < code > ExplocureList code> 成为 < code> Parser (Int - & gt; Int - gt; Int - gt; Int - gt; Dain - gt; Direct; 曝光列表) code >, 但如何帮助您? 您会得到一个需要 4 < code> Int code>, a < code > 和 < code > ExplectlocureList 的函数, 当您给一个 < code> BetaPair 的构建者赋予该函数时, 其构建者会巧妙地想象出一个 < codeb > > > acode > betapair 出来? 。 记得该函数与右相关, 因此, 如果 < code> < beaaper/ dcode > as has kty:
Int -> Int -> Int -> Int -> Direction -> ExposureList -> BetaPair
...它不意味着同样的东西 与:
(Int -> Int -> Int -> Int -> Direction -> ExposureList) -> BetaPair
它实际上意味着:
Int -> (Int -> (Int -> (Int -> (Direction -> (ExposureList -> BetaPair)))))
您可以将 beetalLine
改为 Parser BetaPair
, 这将更有意义。 您可以使用 运算符, 这是 fmap
(在函数箭头下)的同义词, 它允许您将您的 BetaPair
构建器提升到 Parser
furctor, 然后使用辅助配方界面对它应用个别参数。 ; gt;
函数具有此类型 :
(<$>) :: Functor f => (a -> b) -> f a -> f b
在此情况下,您重新升起的第一个参数是 BetaPair
构建器,它将 a
和 b
转化为 BetaPair
“功能”的类型组成部分,产生此特定签名:
(<$>) :: (Int -> (Int -> (Int -> (Int -> (Direction -> (ExposureList -> BetaPair))))))
-> f Int -> f (Int -> (Int -> (Direction -> (ExposureList -> BetaPair))))
如您所看到的, 这里要做的是将一个函数作为左边的参数,并将一个在配方中包装的值作为正确的参数,并将包装的参数应用到函数中。
简单举例说,如果您有 f * Int - & gt; string
,以下表达式如下:
f <$> p_int
... 将解析整数, 以该整数为参数应用函数 < code> > f code >, 并将结果包在配给符中, 所以上面的表达式有类型 < code> parser String code > 。 此位置中的 < code@ lt;$> code> 类型是 :
(<$>) :: (Int -> String) -> Parser Int -> Parser String
所以, 使用 < code @ lt; $> code > 将第一个参数应用到您的构建者 。 那么, 您如何对待其他参数? 那么, 这是 < code@ lt;\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
g <$> p_int <*> p_int
g;$> p_int
表达式将应用 _p_int
的结果来应用 的第一个参数,所以该表达式的类型是 Parker( Int - > String)
。 然后应用下一个参数,具体类型的是 @lt;\gt;
:
(<*>) :: Parser (Int -> String) -> Parser Int -> Parser String
因此,上面整个表达式的类型是 Parser String
。
同样,对于您的情况,您可以让 BetaPair
成为您的 g
, 产生此模式 :
BetaPair <$> one <*> parser <*> per <*> argument <*> to <*> betaPair
如上所述,由此产生的分析者是:
betaLine = string "BETA " *> (BetaPair <$> p_int <*> p_int <*> p_int <*> p_int <*> p_direction <*> p_exposure) <* eol