我的解析器出了什么问题?

时间:2014-02-15 01:51:52

标签: parsing haskell

我在Haskell中为Euler Problem 54创建了一个解析器。除了我的完整文件解析器之外,我的所有解析器都能正常工作。它是一个ReadP解析器,它将它解析为[(Hand, Hand)],我创建了一个Hand类型。它目前将文件解析为[]。我有源代码:

import Text.ParserCombinators.ReadP as Par
import qualified Data.List as L
import qualified Control.Monad as M
import qualified Data.Map as D
import qualified Control.Applicative as A

data Suit=C|D|H|S deriving (Show, Read, Eq, Ord)
data Card=Card Int Suit deriving (Show, Eq, Ord)
data Hand=Hand [Card] deriving (Show, Eq)

ranks=D.fromList [('2', 2), ('3', 3), ('4', 4), ('5', 5), ('6', 6), ('7', 7), ('8', 8),
 ('9', 9), ('T', 10), ('J', 11), ('Q', 12), ('K', 13), ('A', 14)]

allPar=readP_to_S
fstPar s=fst . head . (allPar s)

parCard=do
    rank <- M.liftM (ranks D.!) get
    suit <- M.liftM (read . (:[])) get
    return $ Card rank suit

parHand=do
    first <-parCard
    rest  <-M.replicateM 4 (char ' ' >> parCard)
    return $ Hand $ first:rest

parFile=do
    r<-sepBy (return (,) `M.ap` parHand `M.ap` (char ' ' >> parHand)) (char '\n')
    eof --I have tested with and without this line.
    return r

当我尝试它时(有和没有eof)我得到:

λ <*Main>: fstPar parFile `M.liftM` readFile "poker.txt"
[]

注意:我知道ReadP效率低下,但它是一个小文件,我只想快点。

更新:建议我通过在初始解析后解析eof来尝试它。我已经更新了我的问题以反映这一点,但无论如何都会给出相同的结果。

1 个答案:

答案 0 :(得分:2)

ReadP正在为您提供多个解析,而您正在选择最简单的解析:根本不解析。给定

KC QD 3S 4H 6S 2D 3D 4D 5D AD
AD 5D 4D 3D 2D 6S 4H 3S QD KC

作为输入,通过解析器运行它会产生三个解析:

[ ([],"KC QD 3S 4H 6S 2D 3D 4D 5D AD\nAD 5D 4D 3D 2D 6S 4H 3S QD KC")
, ([(Hand [Card 13 C,Card 12 D,Card 3 S,Card 4 H,Card 6 S],Hand [Card 2 D,Card 3 D,Card 4 D,Card 5 D,Card 14 D])],"\nAD 5D 4D 3D 2D 6S 4H 3S QD KC")
, ([(Hand [Card 13 C,Card 12 D,Card 3 S,Card 4 H,Card 6 S],Hand [Card 2 D,Card 3 D,Card 4 D,Card 5 D,Card 14 D]),(Hand [Card 14 D,Card 5 D,Card 4 D,Card 3 D,Card 2 D],Hand [Card 6 S,Card 4 H,Card 3 S,Card 12 D,Card 13 C])],"")
]

除此之外,您可能想要最后一个,因为它是没有剩余输入的那个。最简单的方法是让你的解析器失败,如果留下任何剩余的输入。幸运的是,这很简单:

fstPar (parFile A.<* eof) `M.liftM` readFile "poker.txt"

也就是说,最后让它运行eof。请注意,现在poker.txt在文件末尾不能有新行。编写更多代码来跳过文件末尾的任何数量的空格应该不会太困难。