FParsec和pipe3使参数显式或添加类型表示法

时间:2019-02-05 14:37:48

标签: parsing f# fparsec

我正在尝试使用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”的参数明确,或者,如果您不希望泛型,则添加类型注释。

  

1 个答案:

答案 0 :(得分:6)

这在FParsec documentation中有介绍;任何解析器都会发生这种情况。原因是因为在.Net类型系统中,允许 function 是通用的,但不允许使用 values -在FParsec中,通常将解析器定义为值(例如,您通常在编写let psomething = ...psomething不使用任何参数)。阅读链接的文档页面以获取整个说明-我不会复制并粘贴整个内容-但简短的版本是您可以执行以下两项操作之一:

  1. 创建一个类似于以下内容的test函数,并确保在解析器的同一源文件中使用了该函数

    let test p str =
        match run p str with
        | Success(result, _, _)   -> printfn "Success: %A" result
        | Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
    
  2. 使用如下类型的注释对解析器进行注释:

    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#将做正确的事情在每种情况下。