为什么这个 Megaparsec 解析器在 GHCi 中工作但不在源文件中编译?
Why does this Megaparsec parser work in GHCi but does not compile in a source file?
我是 Haskell 和 Megaparsec 库的初学者。在解析一行文本时,我需要解析一行中的剩余文本,直到行尾(LF 或 CRLF)。我的想法是使用 some
和 noneOf
但即使在 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"))
编译成功并且 returns 我所期望的:“一行文本”不包括行尾字符。但是,我无法在源文件中编译以下代码
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://whosebug.com/help/minimal-reproducible-example
正如 Silvio Mayolo 在评论中提到的,编译器似乎看不到 "\r\n"
是一个 String
对象,因此是 Char
的列表,因此是一个实例Foldable
class.
λ>
λ> :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
- 多态函数来观察这一点,例如 maximum
或 sum
.
或者,您可以改用显式列表:
> :t noneOf ['\r', '\n']
noneOf ['\r', '\n']
:: (MonadParsec e s m, Token s ~ Char) => m (Token s)
但请注意,如果您启用了 OverloadedLists
,这将有同样类型的欠约束类型问题:
> :set -XOverloadedLists
> :t noneOf ['\r', '\n']
noneOf ['\r', '\n']
:: (Foldable f, MonadParsec e s m,
IsList (f (Token s)),
Item (f (Token s)) ~ Char) =>
m (Token s)
如果您在源文件和 GHCi 之间遇到更多奇怪的差异,通常归结为 GHCi 为方便起见而使用的差异,例如“扩展默认规则”,因此尝试 :set -XNoExtendedDefaultRules
与 :set -XExtendedDefaultRules
有时可以在这种情况下提供帮助。
我是 Haskell 和 Megaparsec 库的初学者。在解析一行文本时,我需要解析一行中的剩余文本,直到行尾(LF 或 CRLF)。我的想法是使用 some
和 noneOf
但即使在 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"))
编译成功并且 returns 我所期望的:“一行文本”不包括行尾字符。但是,我无法在源文件中编译以下代码
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://whosebug.com/help/minimal-reproducible-example
正如 Silvio Mayolo 在评论中提到的,编译器似乎看不到 "\r\n"
是一个 String
对象,因此是 Char
的列表,因此是一个实例Foldable
class.
λ>
λ> :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
- 多态函数来观察这一点,例如 maximum
或 sum
.
或者,您可以改用显式列表:
> :t noneOf ['\r', '\n']
noneOf ['\r', '\n']
:: (MonadParsec e s m, Token s ~ Char) => m (Token s)
但请注意,如果您启用了 OverloadedLists
,这将有同样类型的欠约束类型问题:
> :set -XOverloadedLists
> :t noneOf ['\r', '\n']
noneOf ['\r', '\n']
:: (Foldable f, MonadParsec e s m,
IsList (f (Token s)),
Item (f (Token s)) ~ Char) =>
m (Token s)
如果您在源文件和 GHCi 之间遇到更多奇怪的差异,通常归结为 GHCi 为方便起见而使用的差异,例如“扩展默认规则”,因此尝试 :set -XNoExtendedDefaultRules
与 :set -XExtendedDefaultRules
有时可以在这种情况下提供帮助。