Problems with parsecs types

When writing a parser for a specific computational biology file format, I have some problems.

Here is my code:

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 ' ')) 

Now, if I comment on the definition for betaLine, everything compiles, and I have successfully checked the individual p_int, p_direction, and p_exposure parsers.

But, when this beta equation is present, I get a type error that I don't quite understand. Is my understanding of application error? Ultimately, I want this to return Int -> Int -> Int -> Int -> Direction -> ExposureList, which I can pass to the constructor for BetaPair.

Type error:

 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' 
+4
source share
1 answer

tl; dr : you need this expression:

 betaLine = string "BETA " *> (BetaPair <$> p_int <*> p_int <*> p_int <*> p_int <*> p_direction <*> p_exposure) <* eol 

Read below.


Once again, this is partly a priority issue. What is your current line:

 string "BETA " *> p_int <*> p_int ... 

... is that it creates a parser as follows:

 (string "BETA " *> p_int) <*> (p_int) ... 

This is not the main problem, and, in fact, the semantically incorrect parser above will still give the correct result if the rest of the parser was correct. However, as you say, you have a slight misunderstanding about how <*> works. His signature:

 (<*>) :: Applicative f => f (a -> b) -> fa -> fb 

As you can see, the function should get the function wrapped in the functor as the first argument, which then applies using the value wrapped in the functor in the second argument (thus applied ). When you give it p_int as the first argument at the beginning of your function, it is Parser Int , not Parser (a -> b) , so the types are not checked.

And, in fact, they cannot be printed to check if the goal is what you stated with your reasoning; you want betaLine be Parser (Int -> Int -> Int -> Int -> Direction -> ExposureList) , but how does that help you? You get a function that takes 4 Int s, a Direction and ExposureList , and when you pass this function to the BetaPair constructor, is it magically supposed to build BetaPair from it? Remember that functions are connected on the right, therefore, if the BetaPair constructor is of type:

 Int -> Int -> Int -> Int -> Direction -> ExposureList -> BetaPair 

... this does not mean the same as:

 (Int -> Int -> Int -> Int -> Direction -> ExposureList) -> BetaPair 

This actually means:

 Int -> (Int -> (Int -> (Int -> (Direction -> (ExposureList -> BetaPair))))) 

Instead, you can make betaLine be Parser BetaPair , which will make more sense. You can use the <$> operator, which is synonymous with fmap (under the function arrow), which allows you to raise the BetaPair constructor into the Parser functor, and then apply individual arguments to it using the applicative functional interface. The <$> function has this type:

 (<$>) :: Functor f => (a -> b) -> fa -> fb 

In this case, the first argument you raise is the BetaPair constructor, which converts the types a and b to components of the BetaPair function BetaPair ", which gives this particular signature

 (<$>) :: (Int -> (Int -> (Int -> (Int -> (Direction -> (ExposureList -> BetaPair)))))) -> f Int -> f (Int -> (Int -> (Direction -> (ExposureList -> BetaPair)))) 

As you can see, here <$> will use the function as the left argument, and the value included in the functor as the correct argument, and apply the wrapped argument to the function.

As a simpler example, if you have f :: Int -> String , the following expression:

 f <$> p_int 

... will parse the integer, apply the function f with that integer as an argument, and wrap the result in a functor, so the expression above is of type Parser String . Type <$> in this position:

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

Thus, using <$> applies the first argument to your constructor. So how do you feel about the other arguments? Well, that’s where <*> comes in, and I think that you understand from a type signature what it does: if you bind its use, it will sequentially apply another argument to the function wrapped in the functor on the left, by expanding the functor to the right . So, for a simpler example again; let's say that you have the function g :: Int -> Int -> String and the following expression:

 g <$> p_int <*> p_int 

In the expression g <$> p_int , the result g <$> p_int will be applied to the first argument of g , so the type of this expression is Parser (Int -> String) . Then <*> applies the following argument, with the concrete type <*> being:

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

So, the type of the whole expression is above: Parser String .

Equivalently, for your situation, you can let BetaPair be your g in this case, by getting this template:

 BetaPair <$> one <*> parser <*> per <*> argument <*> to <*> betaPair 

As mentioned above, the resulting parser is thus:

 betaLine = string "BETA " *> (BetaPair <$> p_int <*> p_int <*> p_int <*> p_int <*> p_direction <*> p_exposure) <* eol 
+5
source

Source: https://habr.com/ru/post/1414015/


All Articles