FParsec 和 pipe3 使参数显式或添加类型符号
FParsec and pipe3 make the arguments explicit or add a type notation
我正在尝试使用 FParsec
库中的 pipe3
函数,但出现错误,我不知道如何解决。
鉴于记录
type Point = { x: float; y: float }
和以下解析器
let plistoffloats' =
pipe3 pfloat (pchar ',' .>> spaces) pfloat
(fun first z second -> { x = first; y = second })
我试图实现的是一个解析器,它接收格式为 "1.1, 3.7"
和 returns a Point
的字符串
run plistoffloats' "1.1, 3.7"
输入 : "1.1, 3.7"
期望输出:Point = {x = 1.1; y = 3.7;}
错误:
error FS0030: Value restriction. The value 'plistoffloats'' has been inferred to have generic type
val plistoffloats' : Parser <Point,'__a>
Either make the arguments to 'plistoffloats'' explicit or, if you do not intend for it to be generic, add a type annotation.
使用 pchar
的更简单的示例也不起作用。
let parsesA = pchar 'a'
error FS0030: Value restriction. The value 'parsesA' has been inferred to have generic type
val parsesA : Parser<char,'_a>
Either make the arguments to 'parsesA' explicit or, if you do not intend for it to be generic, add a type annotation.
这在FParsec documentation中有介绍;它会发生在任何解析器上。原因是因为在 .Net 类型系统中,允许 functions 是通用的,但 values 不是——而在 FParsec 中,你是通常将解析器定义为值(例如,您通常编写 let psomething = ...
,其中 psomething
不带参数)。阅读链接的文档页面以获得完整的解释——我不会复制和粘贴整个内容——但简短的版本是你可以做以下两件事之一:
创建一个如下所示的 test
函数,并确保它在您的解析器的同一个源文件中使用:
let test p str =
match run p str with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
使用如下类型注释来注释您的解析器:
type UserState = unit // You might change this later
let plistoffloats' : Parser<_, UserState> =
// ...
听起来您正在尝试执行 #1,但除非您的解析器在同一个源文件中使用 test plistoffloats'
调用,否则 F# 类型推断将无法推断您的用户状态类型并会给你那个错误。
P.S。您可以在此处阅读有关 F# 值限制错误的更多信息:Understanding F# Value Restriction Errors
P.P.S。 Parser<_, UserState>
的第一个位置的 _
并不像 _
在模式匹配等其他上下文中的意思那样表示 "This type could be anything"。相反,类型注释中的 _
表示 "Please infer this type for me so that I don't have to specify it explicitly"。在 FParsec 上下文中,这非常有用,因为您的所有解析器都将 UserState
作为其 second 类型参数,但 first[ 将具有不同的类型=45=] 类型参数。由于 first 类型参数是类型推断可以推断的参数,这意味着您可以将类型 Parser<_, UserState>
复制并粘贴到所有解析器,F# 将执行在每种情况下都是正确的事™。
我正在尝试使用 FParsec
库中的 pipe3
函数,但出现错误,我不知道如何解决。
鉴于记录
type Point = { x: float; y: float }
和以下解析器
let plistoffloats' =
pipe3 pfloat (pchar ',' .>> spaces) pfloat
(fun first z second -> { x = first; y = second })
我试图实现的是一个解析器,它接收格式为 "1.1, 3.7"
和 returns a Point
run plistoffloats' "1.1, 3.7"
输入 : "1.1, 3.7"
期望输出:Point = {x = 1.1; y = 3.7;}
错误:
error FS0030: Value restriction. The value 'plistoffloats'' has been inferred to have generic type val plistoffloats' :
Parser <Point,'__a>
Either make the arguments to 'plistoffloats'' explicit or, if you do not intend for it to be generic, add a type annotation.
使用 pchar
的更简单的示例也不起作用。
let parsesA = pchar 'a'
error FS0030: Value restriction. The value 'parsesA' has been inferred to have generic type val parsesA :
Parser<char,'_a>
Either make the arguments to 'parsesA' explicit or, if you do not intend for it to be generic, add a type annotation.
这在FParsec documentation中有介绍;它会发生在任何解析器上。原因是因为在 .Net 类型系统中,允许 functions 是通用的,但 values 不是——而在 FParsec 中,你是通常将解析器定义为值(例如,您通常编写 let psomething = ...
,其中 psomething
不带参数)。阅读链接的文档页面以获得完整的解释——我不会复制和粘贴整个内容——但简短的版本是你可以做以下两件事之一:
创建一个如下所示的
test
函数,并确保它在您的解析器的同一个源文件中使用:let test p str = match run p str with | Success(result, _, _) -> printfn "Success: %A" result | Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
使用如下类型注释来注释您的解析器:
type UserState = unit // You might change this later let plistoffloats' : Parser<_, UserState> = // ...
听起来您正在尝试执行 #1,但除非您的解析器在同一个源文件中使用 test plistoffloats'
调用,否则 F# 类型推断将无法推断您的用户状态类型并会给你那个错误。
P.S。您可以在此处阅读有关 F# 值限制错误的更多信息:Understanding F# Value Restriction Errors
P.P.S。 Parser<_, UserState>
的第一个位置的 _
并不像 _
在模式匹配等其他上下文中的意思那样表示 "This type could be anything"。相反,类型注释中的 _
表示 "Please infer this type for me so that I don't have to specify it explicitly"。在 FParsec 上下文中,这非常有用,因为您的所有解析器都将 UserState
作为其 second 类型参数,但 first[ 将具有不同的类型=45=] 类型参数。由于 first 类型参数是类型推断可以推断的参数,这意味着您可以将类型 Parser<_, UserState>
复制并粘贴到所有解析器,F# 将执行在每种情况下都是正确的事™。