我正在尝试使用pipe3
库中的FParsec
函数,但是出现一个我不知道如何解决的错误。
提供记录
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"
的字符串并返回Point
run plistoffloats' "1.1, 3.7"
输入:"1.1, 3.7"
所需的输出:Point = {x = 1.1; y = 3.7;}
错误:
错误FS0030:值限制。值'plistoffloats'已推断为具有通用类型 val plistoffloats':
Parser <Point,'__a>
可以使“ plistoffloats”的参数明确,或者,如果您不希望泛型,则添加类型注释。
使用pchar
的简单示例也不起作用。
let parsesA = pchar 'a'
错误FS0030:值限制。值“ parsesA”已推断为具有通用类型 val parsesA:
Parser<char,'_a>
可以使“ parsesA”的参数明确,或者,如果您不希望泛型,则添加类型注释。
答案 0 :(得分:6)
这在FParsec documentation中有介绍;任何解析器都会发生这种情况。原因是因为在.Net类型系统中,允许 function 是通用的,但不允许使用 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>
并不意味着_
在其他情况(例如模式匹配)中的含义是“此类型可以是任何东西”。相反,类型注释中的_
表示“请为我推断此类型,这样我就不必显式指定它”。在FParsec上下文中,这非常有用,因为所有解析器的{em> second 类型参数都将使用UserState
,但 first 类型参数的类型将有所不同。而且,由于 first 类型参数是类型推断可以推断出的参数,因此,您可以将类型Parser<_, UserState>
复制并粘贴到所有解析器中,F#将做正确的事情在每种情况下。