2010-12-21 36 views
2

我目前的項目涉及lexing和解析腳本代碼,因此我使用fslex和fsyacc。 Fslex LexBuffers可以進入LexBuffer<char>LexBuffer<byte>品種,我想可以選擇使用兩者。F#內嵌函數專業化

爲了同時使用,我需要一個類型爲^ buf - > string的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#中嗎?如果是這樣,有人能指向我的正確道路嗎?

謝謝!

回答

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) 
+0

謝謝,托馬斯。我確信必須有一個原因,爲什麼F#函數不能被重載 - 不管它是什麼,我都無法理解。靜態類就足夠了! – Ben 2010-12-21 22:42:02

0

您確定使用不同參數類型重新定義inline函數的策略可以工作嗎?貌似你試圖超載,我...

+0

我當然想超載 - 編譯器似乎並不像第一個明顯的刺超載,不過,抱怨價值'lexeme'的重複定義。內聯看起來很有前途,但我無法弄清楚如何實現它。畢竟,也許這是不可能的。 – Ben 2010-12-21 09:50:02

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"