English 中文(简体)
分析类型问题
原标题:Problems with parsec types

在为特定的计算生物学文件格式撰写解析器时,我遇到了一些麻烦。

这是我的代码:

betaLine = string "BETA " *> p_int <*> p_int  <*> p_int <*> p_int <*> p_direction <*> p_exposure <* eol

p_int = liftA (read :: String -> Int) (many (char    ) *> many1 digit <* many (char    ))

p_direction = liftA mkDirection (many (char    ) *> dir <* many (char    ))
            where dir = oneStringOf [ "1", "-1" ]

p_exposure = liftA (map mkExposure) (many (char    ) *> many1 (oneOf "io") <* many (char    ))

现在,如果我评论一下 乙线的定义, 所有的东西都会编译出来, 我成功地测试了 个体分析器 p_int, p_direction, 和 p_ Excortovure。

但是,当乙线方程式出现时, 我有一个类型错误, 我无法理解。 我对应用 & lt;\\\\\\\ gt; 的理解是否错误? 最终, 我希望它返回 Int - & gt; Int - & gt; Int - & gt; Int - gt; Direct - gt; 曝光列表, 这样我就可以给 BetaPair 的构建者 。

类型错误为 :

Couldn t match expected type `a5 -> a4 -> a3 -> a2 -> a1 -> a0 
            with actual type `Int 
Expected type: Text.Parsec.Prim.ParsecT
                 s0 u0 m0 (a5 -> a4 -> a3 -> a2 -> a1 -> a0)
  Actual type: Text.Parsec.Prim.ParsecT s0 u0 m0 Int
In the second argument of `(*>) , namely `p_int 
In the first argument of `(<*>) , namely `string "BETA " *> p_int 
最佳回答

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 > Parker Int 而不是一个 < code> Parkerer (a- gt;b) , 所以类型不会检查 。

事实上,他们无法输入目标是否是您用推理表达的目标; 您希望 < code> beetalLine 和 < code > ExplocureList 成为 < code> Parser (Int - & gt; Int - gt; Int - gt; Int - gt; Dain - gt; Direct; 曝光列表) , 但如何帮助您? 您会得到一个需要 4 < code> Int , 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> parser String 。 此位置中的 < code@ lt;$> 类型是 :

(<$>) :: (Int -> String) -> Parser Int -> Parser String

所以, 使用 < code @ lt; $> 将第一个参数应用到您的构建者 。 那么, 您如何对待其他参数? 那么, 这是 < 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
问题回答

暂无回答




相关问题
Euler Problem in Haskell -- Can Someone Spot My Error

I m trying my hand at Euler Problem 4 in Haskell. It asks for that largest palindrome formed by multiplying two three-digit numbers. The problem was simple enough, and I thought my Haskell-fu was up ...

How does foldr work?

Can anybody explain how does foldr work? Take these examples: Prelude> foldr (-) 54 [10, 11] 53 Prelude> foldr (x y -> (x+y)/2) 54 [12, 4, 10, 6] 12.0 I am confused about these executions....

Efficient queue in Haskell

How can I efficiently implement a list data structure where I can have 2 views to the head and end of the list, that always point to a head a tail of a list without expensive calls to reverse. i.e: ...

Problem detecting cyclic numbers in Haskell

I am doing problem 61 at project Euler and came up with the following code (to test the case they give): p3 n = n*(n+1) `div` 2 p4 n = n*n p5 n = n*(3*n -1) `div` 2 p6 n = n*(2*n -1) p7 n = n*(5*n -3)...

Ways to get the middle of a list in Haskell?

I ve just started learning about Functional Programming, using Haskel. I m slowly getting through Erik Meijer s lectures on Channel 9 (I ve watched the first 4 so far) and in the 4th video Erik ...

haskell grouping problem

group :: Ord a => [(a, [b])] -> [(a, [b])] I want to look up all pairs that have the same fst, and merge them, by appending all the list of bs together where they have the same a and discarding ...

Closest equivalent to subprocess.communicate in Haskell

I want to do a popen() / python s subprocess.communicate from Haskell - start a program, give it stdin, and get its stdout/stderr. What s the most direct / Haskellish way to do this?