提问人:bookofproofs 提问时间:8/16/2023 更新时间:8/16/2023 访问量:49
将 FParsec 代码移动到 F# 模块不起作用
Moving FParsec code to an F# module does not work
问:
我是 F# 和 FParsec 的新手,在使用 VS 2022 社区版 DotNet 6.0 将我的 FParsec 代码移动到 F# 模块时遇到问题。
我的用例是这样的:我的控制台应用程序解决方案目前由一个我可以毫无问题地构建和运行的单个解决方案组成。现在,我想将代码的某些部分移动到 F# 模块,以便可以重用它。这会导致我无法解决的奇怪类型错误。Program.fs
这是重现我的问题的工作示例。考虑一个控制台应用解决方案,该解决方案由一个包含Program.fs
open FParsec
let p = pstring "foo"
let result = run p "foo"
printfn "%O" result
我可以毫无问题地构建和运行代码。
现在,如果我创建一个这样的模块:MyModule.fs
module MyModule
open FParsec
let p = pstring "foo"
并像这样打开它:Program.fs
open FParsec
open MyModule
let result = run p "foo"
printfn "%O" result
我收到以下两个构建错误:
In MyModule.fs, line 3: Error FS0030 Value restriction. The value 'p' has been inferred to have generic type val p: Parser<string,'_a>
Either make the arguments to 'p' explicit or, if you do not intend for it to be generic, add a type annotation.
In Program.fs, line 3: Error FS0001 Type mismatch. Expecting a 'Parser<'a,unit>' but given a 'Parser<string,obj>'
The type 'unit' does not match the type 'obj'
为什么我会收到这两个错误,尽管与模块拆分的代码在语义上似乎与没有模块的先前代码相同,我该如何解决这些错误?
答:
2赞
Tarmil
8/16/2023
#1
正如 @Gus 在注释中解释的那样,问题在于解析器具有用于用户数据的第二种类型参数,该参数在原始代码中被调用消除了歧义,但在模块化代码中没有。run
您可以通过指定解析器的完整类型来解决此问题:
let p: Parser<string, unit> = pstring "foo"
然后,当您组合多个解析器时,只需指定一次,它就会为使用它或它使用的所有解析器消除歧义。它通常在最终解析器上完成。
let p1 = pstring "foo"
let p2 = pstring "bar"
let p: Parser<string, unit> = p1 <|> p2
评论
0赞
bookofproofs
8/16/2023
谢谢,它解决了我的问题。我自己无法弄清楚显式键入 p 变量的正确语法,因为 F# 编译器错误显示“Parser<string,'_a>”而不是“Parser<string,unit>”,这误导了像我这样的新手:-)。
评论
run