2014-06-13 57 views
1

我想編寫一個函數,它接受一對字符串並將第二個元素轉換爲格式。我以爲我可以使用format_of_string函數,但似乎是行不通的。這是一個簡化版本:OCaml函數format_of_string未按預期工作

let pp fmt (e:string * string) = 
    let msg = format_of_string (snd e) in Format.fprintf fmt (" - "^^msg^^"@.");; 
          ^^^^^^^ 
Error: This expression has type string but an expression was expected of type 
    ('a, 'b, 'c, 'd, 'e, 'f) format6 

有沒有辦法讓我的函數接受一對字符串?

+0

您應該閱讀http://caml.inria.fr/mantis/view.php?id=5591 –

+0

的錯誤報告的確如此!這提供了一個使用'Scanf.format_from_string'的解決方案。非常感謝 ! – Anne

回答

2

我回答我自己的問題,但是我在上面的評論中發現了@Pascal Cuoq的解決方案。

問題是隻有編譯器能夠分析它才能計算格式類型,編譯器才能將字符串轉換爲格式。這就是爲什麼format_of_string只能處理已知的字符串。因此,上述問題的第一個解決方案是在調用函數之前轉換字符串,當它已知時,但它不是問題的真正答案。

最好解決方案是使用Scanf.format_from_string

val format_from_string : string -> 
    ('a, 'b, 'c, 'd, 'e, 'f) format6 -> ('a, 'b, 'c, 'd, 'e, 'f) format6 

其中是第二參數具有相同的類型不是預期格式。因此,例如,在上面的例子中,因爲字符串souldn't包括任何%的說法,那就是:

let pp fmt (e:string * string) = 
    let msg = Scanf.format_from_string (snd e) "" in 
    Format.fprintf fmt (" - "^^msg^^"@.");; 

然後調用這個函數是正確的只有這沒有%參數字符串:

# Format.printf "%a" pp ("", "abc");; 
- abc 
- : unit =() 

但它否則會引發一個異常:

# Format.printf "%a" pp ("", "abc%d");; 
Exception: 
Scanf.Scan_failure "format read 'abc%d' does not match specification ''". 
1

您不能將格式作爲參數,並將其與其他位字符串相關聯並將其用作格式:類型系統不允許表示這種情況。

只要想一想" - "應該是"%"的情況。這是一個不同的例子,但它具有相同的類型,所以它必須被相同的機制接受或拒絕。

下面的行是否做你最初的目標?

let pp fmt f x = Format.printf fmt " - %[email protected]" f x ;; 
+0

我不確定,因爲我想要的只是能夠在我的字符串中使用「@」和「@」。但是,如果我在調用該函數之前在我的原始字符串上調用'format_of_string',那麼這樣做是行得通的。它不太乾淨,但工作。不管怎麼說,還是要謝謝你。 – Anne

2

直覺相反,format_of_string確實而不是string轉換爲格式(這是不可能的,因爲格式類型在編譯時會進行類型檢查,但在編譯時不知道該字符串的內容; Scanf.format_from_string在運行時檢查它)。

相反,它的類型是val format_of_string : ('a, 'b, 'c, 'd, 'e, 'f) format6 -> ('a, 'b, 'c, 'd, 'e, 'f) format6 - 它採用格式並返回一個格式,這意味着它基本上是格式爲的身份識別功能。

這樣的功能有什麼用?對於OCaml中的表達式而言,OCaml中的字符串常量「超載」。它們可以是字符串類型或格式類型。大多數情況下,它被推斷爲一個字符串類型。但是,如果您在需要格式類型的上下文中使用它,例如一個參數Printf.printf,編譯器推斷它爲一種格式類型。但是如果你使用它來初始化一個變量呢?編譯器「默認」爲一個字符串類型。但是,有時可能需要初始化格式類型的變量。您不能輕易使用類型註釋,因爲格式的類型非常複雜,您不需要明確指定它。相反,您可以通過format_of_string傳遞字符串字面量,它會「強制」編譯器將其推斷爲格式類型,但以其他方式返回值不變。

P.S.你有可能在參數中使用格式而不是字符串嗎?

+0

是的,我的功能可能採取了一種格式,這是我的第一個解決方案,但使用Scanf.format_from_string是一個更好的方法,因爲它在我的情況下更清晰(請參閱我的答案)。 – Anne