F# Inline Function Specialization
My current project involves lexing and parsing script code, and as such I'm 开发者_如何学Cusing fslex and fsyacc. Fslex LexBuffers can come in either LexBuffer<char>
and LexBuffer<byte>
varieties, and I'd like to have the option to use both.
In order to user both, I need a lexeme function of type ^buf -> string. Thus far, my attempts at specialization have looked like:
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)
I'm getting a type error stating that the function body should be of type ^buf -> string
, but the inferred type is just string
. Clearly, I'm doing something (majorly?) wrong.
Is what I'm attempting even possible in F#? If so, can someone point me to the proper path?
Thanks!
Functions and members marked as inline
cannot be overloaded, so your original strategy won't work. You need to write different code for both of the declarations, so you need to use overloading (if you want to write this without boxing and dynamic type tests).
If you're using standard F# tools, then the type you'll get as a buffer will always be LexBuffer<'T>
and you want to have two overloads based on the type argument. In this case, you don't need the static member constraints at all and can write just:
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)
Are you sure this strategy of redefining inline
functions with different argument types can work? Looks like you're trying to overload to me...
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"
精彩评论