首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Attoparsec挂起

Attoparsec挂起
EN

Stack Overflow用户
提问于 2022-02-14 19:52:02
回答 1查看 77关注 0票数 4

我目前正在解决AOC第四项任务,输入格式如下,用逗号分隔的数字行,然后是5x5矩阵:

代码语言:javascript
复制
27,14,70,7,85,66,65

31 23 52 26  8
27 89 37 80 46
97 19 63 34 79
13 59 45 12 73
42 25 22  6 39

27 71 24  3  0
79 42 32 72 62
99 52 11 92 33
38 22 16 44 39
35 26 76 49 58

27 71 24 ...

我有以下解析器:

代码语言:javascript
复制
{-# LANGUAGE TupleSections #-}

module Lib4Parse (parseAll) where

import Control.Applicative
import Control.Monad
import Data.Attoparsec.ByteString.Char8 (Parser, Result, char, count, decimal, eitherResult, endOfInput, endOfLine, isDigit, isEndOfLine, isSpace, many', many1, option, parse, parseOnly, parseTest, scientific, sepBy, signed, skipMany, skipMany1, skipSpace, skipWhile, space, takeTill)
import qualified Data.ByteString as B

newtype BoardEntry = MkBoardEntry (Bool, Int) deriving (Show, Eq)

newtype Board = MkBoard [[BoardEntry]] deriving (Show, Eq)

parseAll :: B.ByteString -> Maybe ([Int], [Board])
parseAll input =
  either (const Nothing) Just $
    parseOnly ((,) <$> inputNumbers <*> boards) input

inputNumbers :: Parser [Int]
inputNumbers = decimal `sepBy` char ','

boardEntry :: Parser [BoardEntry]
boardEntry = map (\x -> MkBoardEntry (False, x)) <$> (decimal `sepBy` many1 (char ' '))

board :: Parser Board
board =
  MkBoard <$> count 5 (boardEntry <* (skipWhile isSpace <|> endOfInput))

boards :: Parser [Board]
boards = takeTill isDigit >> many board

问题是,当我在板函数中使用many时,它会挂起(当调用parseAll函数时)。但是,如果董事会的功能看起来像这样,它可以工作:

代码语言:javascript
复制
boards :: Parser [Board]
boards = takeTill isDigit >> count 5 board

然而,我想解析所有的董事会,而不仅仅是指定的数目。

问题

这个挂起的问题是什么,怎么解决呢?

如何调试这样的解析器?-我无法调试它,因为我不知道解析器在做什么。有什么技巧和技巧来调试这样的解析器吗?

EN

回答 1

Stack Overflow用户

发布于 2022-02-14 23:39:47

根据@Carl的评论,问题是board可以匹配空输入,所以当它到达输入末尾时,many board试图解析无限多个空板。具体来说,一个board匹配五个boardEntry,但是boardEntry可以匹配零数字(即一个空字符串)。如果所有行都应该那么长,则可以要求它匹配五个数字,或者可以将sepBy升级到sepBy1,以确保至少匹配一个数字:

代码语言:javascript
复制
boardEntry :: Parser [BoardEntry]
boardEntry = map (\x -> MkBoardEntry (False, x)) <$> (decimal `sepBy1` many1 (char ' '))

我常用的调试解析器的方法是孤立地运行小块:

代码语言:javascript
复制
> :set -XOverloadedStrings
> parseOnly boardEntry "1 2 3 4 5\n"
Right [MkBoardEntry (False,1),...]

在这种情况下,这没有多大帮助。在我走得太远之前,我碰巧在boardEntry中发现了这个问题。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71117525

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档