微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么这个 Megaparsec 解析器可以在 GHCi 中工作,但不能在源文件中编译?

如何解决为什么这个 Megaparsec 解析器可以在 GHCi 中工作,但不能在源文件中编译?

我是 Haskell 和 Megaparsec 库的初学者。在解析一行文本时,我需要解析行中的剩余文本,直到行尾(LF 或 CRLF)。我的想法是使用 somenoneOf 但即使在 GHCi 中测试后也无法编译代码,如下所示:

λ> import Data.Text (Text,pack)
λ> import Data.Void
λ> import Text.Megaparsec as M
λ> import Text.Megaparsec.Char as M
λ> import qualified Text.Megaparsec.Char.Lexer as L
λ> type Parser = Parsec Void Text
λ> 
λ> parse (some (noneOf "\r\n")) "" (pack "a line of text\r\n")
Right "a line of text"
λ> parse (some (noneOf "\r\n")) "" (pack "a line of text\n")
Right "a line of text"

因此解析器 (some (noneOf "\r\n")) 编译成功并返回我预期的内容:“一行文本”,不包括行尾字符。但是,我无法在源文件中编译以下代码

pLineValue :: Parser Text
pLineValue = do
    str <- (some (noneOf "\r\n"))
    return (pack str)

编译器报错如下:

    • Ambiguous type variable ‘f0’ arising from a use of ‘noneOf’
      prevents the constraint ‘(Foldable f0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘f0’ should be.
      These potential instances exist:
        instance Foldable (Either a) -- Defined in ‘Data.Foldable’
        instance Foldable Maybe -- Defined in ‘Data.Foldable’
        instance Foldable ((,) a) -- Defined in ‘Data.Foldable’
        ...plus one other
        ...plus 37 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the first argument of ‘some’,namely ‘(noneOf "\r\n")’
      In a stmt of a 'do' block: str <- (some (noneOf "\r\n"))
      In the expression:
        do str <- (some (noneOf "\r\n"))
           return (pack str)
   |
78 |     str <- (some (noneOf "\r\n"))
   |                   ^^^^^^^^^^^^^

我做错了什么?源文件中的正确语法是什么?或者有没有更好的方法来解析剩余的文本,但不包括 LF 或 CRLF 结尾? 我很感激任何帮助,谢谢。

解决方法

您的符号之一似乎不是来自您期望的地方。但是,很难确切地说出问题出在哪里,因为您只提供了一部分已编译的代码,而不是一些自包含的内容。

https://stackoverflow.com/help/minimal-reproducible-example

正如 Silvio Mayolo 在评论中提到的,编译器似乎无法看到 "\r\n" 是一个 String 对象,因此是一个 Char 列表,因此是 Foldable 的一个实例{1}} 节课。

 λ> 
 λ> :type M.noneOf
M.noneOf
  :: (Foldable f,MonadParsec e s m) => f (Token s) -> m (Token s)
 λ> 

下面的代码非常相似,但编译(和运行)完美无缺:

import  Data.Text (Text,pack,unpack)
import  Data.Void
import  qualified  Text.Megaparsec  as  M

type MyParser = M.Parsec Void Text

pLineValue :: MyParser Text
pLineValue = do
    str <- (M.some (M.noneOf "\r\n"))
    return (pack str)


main :: IO ()
main = do
    let resT = M.parse pLineValue "-" (pack "a line of text\r\n")
        resS = case resT of
                 Right txt  ->  unpack txt
                 Left  _    ->  "ERROR"
    putStrLn $ "resS = " ++ resS


,

noneOf 接受一个任意的 Foldable 容器:

noneOf :: (Foldable f,MonadParsec e s m) => f (Token s) -> m (Token s)

"\r\n" 通常是一个 String,它是一个 Char 的列表:

> :t "\r\n"
"\r\n" :: [Char]

> :i String
type String = [Char]    -- Defined in ‘GHC.Base’

但是,如果您启用了 OverloadedStrings,则 "\r\n" 可以是任何 IsString 实例:

> :set -XOverloadedStrings
> :t "\r\n"
"\r\n" :: IsString p => p

因此对 noneOf 的调用是不明确的,因为容器的类型没有固定:

> :t noneOf "\r\n"
noneOf "\r\n"
  :: (Foldable f,MonadParsec e s m,IsString (f (Token s))) =>
     m (Token s)

简单的解决方法是添加类型注解:

> :t noneOf ("\r\n" :: [Char])
noneOf ("\r\n" :: [Char])
  :: (MonadParsec e s m,Token s ~ Char) => m (Token s)

您可以使用任何 Foldable- 或 Traversable- 多态函数(如 maximumsum)观察这一点。

或者,您可以使用显式列表:

> :t noneOf ['\r','\n']
noneOf ['\r','\n']
  :: (MonadParsec e s m,Token s ~ Char) => m (Token s)

但请注意,如果您启用了 OverloadedLists,这将具有相同类型的欠约束类型问题:

> :set -XOverloadedLists
> :t noneOf ['\r','\n']
  :: (Foldable f,IsList (f (Token s)),Item (f (Token s)) ~ Char) =>
     m (Token s)

如果您在源文件和 GHCi 之间遇到更奇怪的差异,通常归结为 GHCi 为方便起见而使用的差异,例如“扩展默认规则”,因此尝试使用 :set -XNoExtendedDefaultRules 与 {{1} } 在这种情况下有时会有所帮助。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。