首页 > 解决方案 > FParsec 和 pipe3 使参数显式或添加类型表示法

问题描述

我正在尝试使用库中的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' 的参数显式,或者,如果您不打算使其成为泛型,则添加类型注释。

标签: parsingf#fparsec

解决方案


这在FParsec 文档中有介绍;任何解析器都会发生这种情况。原因是因为在.Net 类型系统中,函数被允许是通用的,但不是——而在FParsec 中,您通常将解析器定义为值(例如,您通常编写不带参数的let psomething = ...where )。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# 类型推断将无法推断您的用户状态类型并且会给您该错误。

PS您可以在此处阅读有关 F# 值限制错误的更多信息:了解 F# 值限制错误

PPS 的_第一个位置Parser<_, UserState>并不意味着“这种类型可以是任何东西”,就像_在模式匹配等其他上下文中所表示的那样。相反,_在类型注释中意味着“请为我推断此类型,以便我不必明确指定它”。在 FParsec 上下文中,这非常有用,因为您的所有解析器都将具有UserState第二个类型参数,但第一个类型参数将具有不同的类型。由于第一个类型参数是类型推断可以推断的,这意味着您可以将类型复制并粘贴Parser<_, UserState>到所有解析器中,并且 F# 在每种情况下都会做正确的事情。


推荐阅读