2

我当前的项目涉及词法分析和解析脚本代码,因此我正在使用 fslex 和 fsyacc。Fslex LexBuffers 可以有两种形式LexBuffer<char>LexBuffer<byte>我希望可以选择同时使用这两种方法。

为了同时使用两者,我需要一个 ^buf -> 字符串类型的词位函数。到目前为止,我的专业化尝试看起来像:

let inline lexeme (lexbuf: ^buf) : ^buf -> string where ^buf : (member Lexeme: char array) =
  new System.String(lexbuf.Lexeme)

let inline lexeme (lexbuf: ^buf) : ^buf -> string where ^buf : (member Lexeme: byte array) =
  System.Text.Encoding.UTF8.GetString(lexbuf.Lexeme)

我收到一个类型错误,指出函数体应该是 type ^buf -> string,但推断的类型是 just string。显然,我做错了什么(主要是?)。

我正在尝试在 F# 中甚至可能吗?如果是这样,有人可以指出我正确的路径吗?

谢谢!

4

3 回答 3

2

标记为的函数和成员inline不能重载,因此您的原始策略将不起作用。您需要为这两个声明编写不同的代码,因此您需要使用重载(如果您想在没有装箱和动态类型测试的情况下编写它)。

如果您使用标准 F# 工具,那么您将作为缓冲区获得的类型将始终是LexBuffer<'T>,并且您希望根据类型参数有两个重载。在这种情况下,您根本不需要静态成员约束,只需编写:

type Utils = 
  static member lexeme(buf:LexBuffer<char>) = 
    new System.String(buf.Lexeme)
  static member lexeme(buf:LexBuffer<byte>) = 
    System.Text.Encoding.UTF8.GetString(buf.Lexeme)
于 2010-12-21T13:11:52.467 回答
0

你确定这种inline用不同参数类型重新定义函数的策略可行吗?看起来你想对我超载...

于 2010-12-21T09:45:55.037 回答
0
type LexBuffer<'a>(data : 'a []) =
  member this.Lexeme = data

let lexeme (buf : LexBuffer<'a>) =
  match box buf.Lexeme with
  | :? (char array) as chArr ->
      new System.String(chArr)
  | :? (byte array) as byArr ->
      System.Text.Encoding.UTF8.GetString(byArr)
  | _ -> invalidArg "buf" "must be either char or byte LexBuffer"

new LexBuffer<byte>([| 97uy; 98uy; 99uy |])
|> lexeme
|> printfn "%A"

new LexBuffer<char>([| 'a'; 'b'; 'c' |])
|> lexeme
|> printfn "%A"
于 2010-12-21T12:33:22.137 回答