Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell Parsec lookahead处理int_Haskell_Parsec - Fatal编程技术网

Haskell Parsec lookahead处理int

Haskell Parsec lookahead处理int,haskell,parsec,Haskell,Parsec,我正在开发一个Parsec解析器来处理一种有点复杂的数据文件格式(我无法控制这种格式) 我已经取得了很大的进步,但我目前仍坚持以下几点 我需要能够解析这样一行代码: 4 0.123 1.452 0.667 * 3.460 149 - - p_logProb = liftA mkScore (lp <?> "logProb") where lp = try dub <|> string "*" dub = (

我正在开发一个Parsec解析器来处理一种有点复杂的数据文件格式(我无法控制这种格式)

我已经取得了很大的进步,但我目前仍坚持以下几点

我需要能够解析这样一行代码:

4  0.123  1.452  0.667  *  3.460  149 - -
p_logProb = liftA mkScore (lp <?> "logProb")
          where lp = try dub <|> string "*"
                dub = (++) <$> ((++) <$> many1 digit <*> string ".") <*> many1 digit
语义上,
4
是节点枚举,
浮动
*
是负对数概率(因此,
*
表示概率为零的负对数)。
149
和减号实际上是垃圾,我可以丢弃它们,但我至少需要确保它们不会破坏解析器

以下是我目前掌握的情况:

这可以处理我提到的“垃圾”。它可能更简单,但它可以自己工作

 emAnnotationSet = (,,) <$> p_int  <*>
                           (reqSpaces *> char '-') <*>
                           (reqSpaces *> char '-')
最后,我尝试将
logProb
条目与后面的
emAnnotationSet
(以整数开头)分开,如下所示:

hmmMatchEmissions     = optSpaces *> (V.fromList <$> sepBy p_logProb reqSpaces) 
                      <* optSpaces <* emAnnotationSet <* eol 
                      <?> "matchEmissions"

列196对应于减号前面的整数后面的空格,因此我很清楚问题在于
p_logProb
解析器正在使用整数。我如何解决这个问题,使
p\u logProb
解析器正确地使用了lookahead,从而将该输入留给
emAnnotationSet
解析器?

我不能完全确定您的问题。但是,要解析基于您的描述给出的行,使用
Text.Parsec.Token1
中定义的现有lexer并将它们连接在一起会容易得多

下面的代码将该行解析为一个行数据类型,如果需要,您可以从那里进一步处理它。在解析之前,它没有尝试过滤掉
-
和整数,而是使用
parseEntry
解析器,如果它是浮点值,则只返回一个
Double
,对于
*
仅返回0,对于整数和破折号则返回
Nothing
。然后使用
catMaybes
对其进行非常简单的过滤

代码如下:

module Test where
import Text.Parsec
import qualified Text.Parsec.Token as P
import Text.Parsec.Language (haskellDef)
import Control.Applicative ((<$>))
import Data.Maybe (catMaybes)
lexer = P.makeTokenParser haskellDef

parseFloat = P.float lexer
parseInteger = P.natural lexer 

whiteSpace = P.whiteSpace lexer

parseEntry = try (Just <$> parseFloat)
             <|> try (const (Just 0) <$> (char '*' >> whiteSpace))
             <|> try (const Nothing <$> (char '-' >> whiteSpace))
             <|> (const Nothing <$> parseInteger)


data Line = Line {
      lineNodeNum :: Integer
    , negativeLogProbabilities :: [Double]
    } deriving (Show)

parseLine = do
  nodeNum <- parseInteger
  whiteSpace
  probabilities <- catMaybes <$> many1 parseEntry
  return $ Line { lineNodeNum = nodeNum, negativeLogProbabilities = probabilities }
唯一可能(也可能不是)出现问题的问题是,它将
*-
作为两个不同的标记进行解析,而不是在解析时失败。乙二醇

*Test> parseTest parseLine "4  0.123  1.452  0.667  *  3.460  149 - -*"
Line {lineNodeNum = 4, negativeLogProbabilities = [0.123,1.452,0.667,0.0,3.46,0.0]}

注意日志概率末尾的额外
0.0

终止概率的整数不能被误认为概率,因为它不包含小数点。
lexeme
combinator将解析器转换为跳过尾随空格的解析器

import Text.Parsec
import Text.Parsec.String
import Data.Char
import Control.Applicative ( (<$>), (<*>), (<$), (<*), (*>) )

fractional :: Fractional a => Parser a
fractional = try $ do
  n <- fromIntegral <$> decimal
  char '.'
  f <- foldr (\d f -> (f + fromIntegral (digitToInt d))/10.0) 0.0 <$> many1 digit  
  return $ n + f

decimal :: Parser Int
decimal = foldl (\n d -> 10 * n + digitToInt d) 0 <$> many1 digit

lexeme :: Parser a -> Parser a
lexeme p = p <* skipMany (char ' ')

data Row = Row Int [Maybe Double]
           deriving ( Show )

probability :: Fractional a => Parser (Maybe a)
probability = (Just <$> fractional) <|> (Nothing <$ char '*')

junk = lexeme decimal <* count 2 (lexeme $ char '-')

row :: Parser Row
row = Row <$> lexeme decimal <*> many1 (lexeme probability) <* junk

rows :: Parser [Row]
rows = spaces *> sepEndBy row (lexeme newline) <* eof

隐马尔可夫模型。。。问题是,“*”不应解析为0.0;它是0的负对数,所以它实际上是无穷大(被视为
negLogZero
)。而且,从列表末尾去掉一个无关的
0.0
似乎真的很不幸。。。我还对使用现有的lexer持谨慎态度,因为这种文件格式的浮点实际上不是任意的浮点(例如,它们不能是负数,并且不允许使用e-notation)。实际上,我需要解析一组标记,它们要么是“*”要么是使用十进制表示法的浮点,后跟一个整数(然后是两个减号)。这就是我被卡住的地方。啊,我误解了你关于额外0.0的观点。不,我不担心出现
-*
。我仍然担心使用lexer。我不想在允许的双精度和
*
s列表中允许任意整数。为了澄清,int和减号总是在行的末尾,紧跟在
eol
之前。我想我可以得到我需要的。那些星号实际上不应该变成什么;他们和双打实际上成了得分的例子,但我已经为他们设置了构造函数,所以这应该是一个微不足道的改变。谢谢
*Test> parseTest parseLine "4  0.123  1.452  0.667  *  3.460  149 - -*"
Line {lineNodeNum = 4, negativeLogProbabilities = [0.123,1.452,0.667,0.0,3.46,0.0]}
import Text.Parsec
import Text.Parsec.String
import Data.Char
import Control.Applicative ( (<$>), (<*>), (<$), (<*), (*>) )

fractional :: Fractional a => Parser a
fractional = try $ do
  n <- fromIntegral <$> decimal
  char '.'
  f <- foldr (\d f -> (f + fromIntegral (digitToInt d))/10.0) 0.0 <$> many1 digit  
  return $ n + f

decimal :: Parser Int
decimal = foldl (\n d -> 10 * n + digitToInt d) 0 <$> many1 digit

lexeme :: Parser a -> Parser a
lexeme p = p <* skipMany (char ' ')

data Row = Row Int [Maybe Double]
           deriving ( Show )

probability :: Fractional a => Parser (Maybe a)
probability = (Just <$> fractional) <|> (Nothing <$ char '*')

junk = lexeme decimal <* count 2 (lexeme $ char '-')

row :: Parser Row
row = Row <$> lexeme decimal <*> many1 (lexeme probability) <* junk

rows :: Parser [Row]
rows = spaces *> sepEndBy row (lexeme newline) <* eof
*Main> parseTest rows "4 0.123 1.234 2.345 149 - -\n5 0.123 * 2.345 149 - -" 
[Row 4 [Just 0.123,Just 1.234,Just 2.345],Row 5 [Just 0.123,Nothing,Just 2.345]]