F#内联函数专业化

时间:2010-12-21 06:47:56

标签: function f# inline specialization fslex

我当前的项目涉及lexing和解析脚本代码,因此我使用的是fslex和fsyacc。 Fslex LexBuffers可以有LexBuffer<char>LexBuffer<byte>种类,我希望可以同时使用它们。

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

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)

我收到一个类型错误,指出函数体应该是^buf -> string类型,但推断类型只是string。显然,我正在做某事(主要是?)错误。

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

谢谢!

3 个答案:

答案 0 :(得分: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)

答案 1 :(得分:0)

您确定使用不同参数类型重新定义inline函数的策略是否有效?看起来你正试图给我超载......

答案 2 :(得分: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"