0

我正在尝试学习使用 attoparsec。我正在尝试解析以下格式的文本文件:

id int
call_uuid string 30

我的代码在这里:

{-# LANGUAGE OverloadedStrings #-}

import Control.Applicative ((<$>))
import Data.Char (isDigit, isAlpha)
import Data.Attoparsec.Text (Parser, many1, letter, many', char, digit, string, 
                             (.*>), skipSpace, peekChar, decimal, 
                             isHorizontalSpace, skipWhile, parseOnly)
import qualified Data.Text.IO as T

schema :: Parser [(String, String, Maybe Int)]
schema = many1 typelines
  where
    colname = do
      c <- letter
      cs <- takeWhile (\x -> isDigit x || isAlpha x || x == '_')
      return (c:cs)

    int :: (Integral a, Read a) => Parser a
    int = read <$> decimal

    typelines = do
      cname <- colname
      skipWhile isHorizontalSpace
      tname <- takeWhile isAlpha
      skipWhile isHorizontalSpace
      c <- peekChar
      if c == '\n'
        then do { char '\n'; return (cname, tname, Nothing);}
        else do
          num <- int
          char '\n'
          return (cname, tname, num)

readDBTypes :: String -> IO [(String, String, Maybe Int)]
readDBTypes filename = do
  content <- T.readFile filename
  case (parseOnly schema content) of
    Left err -> do 
      print err
      return []
    Right v -> return v

main :: IO ()
main = do
  myLines <- readDBTypes "schema2.out"
  mapM_ print myLines

运行时,出现以下编译器错误(ghc 7.4)

$ runhaskell schema.hs

schema.hs:18:13:
    Couldn't match expected type `attoparsec-0.10.4.0:Data.Attoparsec.Internal.Types.Parser
                                    Data.Text.Internal.Text t0'
                with actual type `[a0] -> [a0]'
    In the return type of a call of `takeWhile'
    Probable cause: `takeWhile' is applied to too few arguments
    In a stmt of a 'do' block:
      cs <- takeWhile (\ x -> isDigit x || isAlpha x || x == '_')
    In the expression:
      do { c <- letter;
           cs <- takeWhile (\ x -> isDigit x || isAlpha x || x == '_');
           return (c : cs) }

schema.hs:22:20:
    Could not deduce (Integral String) arising from a use of `decimal'
    from the context (Integral a, Read a)
      bound by the type signature for
                 int :: (Integral a, Read a) => Parser a
      at schema.hs:22:5-26
    Possible fix:
      add (Integral String) to the context of
        the type signature for int :: (Integral a, Read a) => Parser a
      or add an instance declaration for (Integral String)
    In the second argument of `(<$>)', namely `decimal'
    In the expression: read <$> decimal
    In an equation for `int': int = read <$> decimal

schema.hs:27:16:
    Couldn't match expected type `attoparsec-0.10.4.0:Data.Attoparsec.Internal.Types.Parser
                                    Data.Text.Internal.Text t0'
                with actual type `[a0] -> [a0]'
    In the return type of a call of `takeWhile'
    Probable cause: `takeWhile' is applied to too few arguments
    In a stmt of a 'do' block: tname <- takeWhile isAlpha
    In the expression:
      do { cname <- colname;
           skipWhile isHorizontalSpace;
           tname <- takeWhile isAlpha;
           skipWhile isHorizontalSpace;
           .... }

我不确定这是否与我的安装中损坏的软件包有关,或者我是否不了解这些类型。提前致谢!

4

2 回答 2

4

这里有2个错误,首先takeWhile(a -> Bool) -> [a] -> [a]由前奏定义的。你可能想要takeWhileData.Auttoparsec.Text但你必须先导入它并隐藏前奏版本。

import Prelude hiding (takeWhile)
import Data.Attoparsec.Text (takeWhile)

但如果这段代码变得更大,我会建议

import qualified Data.AttoParsec.Text (takeWhile) as AP

然后只需使用AP.takeWhile它,因为当您不必四处奔走查看 Prelude 中隐藏的内容时,它更具可读性。

Nextdecimal将自行返回Integral a所有内容,因此请不要对其进行 fmap read。您实际上并不需要该int功能。Haskell 的类型检查器足够聪明,可以Integral aInt你的函数统一,所以只需使用普通的 old decimal

于 2013-06-14T23:41:52.130 回答
2

您需要从 导入takeWhileData.Attoparsec.Text否则编译器将使用Prelude.

import Data.Attoparsec.Text (takeWhile)
import Prelude hiding (takeWhile)

decimal已经返回一个Integral a;不需要read

int :: Integral a => Parser a
int = decimal
于 2013-06-14T23:41:37.557 回答