我試圖傳入一個字符串來獲取反轉的字符串。爲什麼我不能這樣做:爲字符串OCaml函數參數模式匹配
let rec reverse x =
match x with
| "" -> ""
| e^s -> (reverse s)^e;;
編譯器說這是一個語法錯誤。我不能使用^
來解構參數嗎?
我試圖傳入一個字符串來獲取反轉的字符串。爲什麼我不能這樣做:爲字符串OCaml函數參數模式匹配
let rec reverse x =
match x with
| "" -> ""
| e^s -> (reverse s)^e;;
編譯器說這是一個語法錯誤。我不能使用^
來解構參數嗎?
這樣做的原因是字符串沒有以與列表相同的方式表示爲數據類型。因此,雖然cons(:)是構造函數,但^是而不是。相反,字符串被表示爲沒有遞歸定義的低級別類型(如列表所示)。有一種方法可以將字符串匹配爲字符列表,使用SML中的函數(可以在OCaml中編寫),稱爲'explode'和'implode',分別將字符串轉換爲char列表,反之亦然。 Here's an example implementation of them.
謝謝。但無論如何,像C++那樣「超載」操作數呢?這絕對會更好的抽象。 – lkahtz 2012-03-25 22:33:18
沒有辦法讓操作員過載。字符串被定義爲較低級別的類型,並且當它們基本上不屬於歸納定義的類型時,不能將它們人爲地強制爲數據類型。 – 2012-03-25 23:12:12
當您編寫模式匹配表達式時,不能在模式中使用任意函數。您只能使用構造函數,它看起來像未評估的函數。例如,函數「+」在整數上定義。所以表達式1+2
被評估並給出3;評估功能「+」,所以你不能匹配x+y
。這裏是一個試圖定義自然數的函數,檢查數量是否爲零:
let f x = match x with
| 0 -> false
| a+1 -> true
;;
這可不行!出於同樣的原因,您的字符串示例無法工作。函數「^」是在字符串上計算的,它不是構造函數。
x+1
上的匹配僅適用於未評估數字的符號表達由未評估的運算符+
和符號常量1
構成的符號表達式。這在OCAML中並非如此。整數通過機器編號直接實現。
當你匹配變體類型時,你匹配構造函數,這是未評估的表達式。例如:
# let f x = match x with
| Some x -> x+1
| None -> 0
;;
val f : int option -> int = <fun>
此工作,因爲該'a option
類型是做出來的一個象徵性的表達方式,如Some x
。在這裏,Some
不是一個被評估的函數,它提供了一些其他的值,而是一個「構造函數」,你可以把它看作是一個永遠不會被評估的函數。表達式Some 3
不再被評估;它保持原樣。只有在這樣的功能上,您才能進行模式匹配。
列表也是構造函數構建的符號,未評估的表達式;構造函數是::
。 x :: y :: []
的結果是一個未評估的表達式,僅爲了美觀方便而由列表[x;y]
表示。出於這個原因,你可以在列表上進行模式匹配。
感謝您的回答。如果可以提及OCaml中字符串的模式匹配是否可行並且如何實現,那將會很好。 – 2017-09-25 19:11:38
作爲Kristopher Micinski explained,由於它們不是列表,因此無法對字符串進行模式匹配。
但是,您可以使用explode
將它們轉換爲列表。下面是使用explode
和其對應implode
您reverse
功能與模式匹配:
let rec reverse str =
match explode str with
[] -> ""
| h::t -> reverse (implode t)^string_of_char h
使用方法如下:
let() =
let text = "Stack Overflow ♥ OCaml" in
Printf.printf "Regular: %s\n" text;
Printf.printf "Reversed: %s\n" (reverse text)
這表明,它適用於單字節字符而不是多字節的人。
這裏是explode
和implode
與助手一起的方法:
let string_of_char c = String.make 1 c
(* Converts a string to a list of chars *)
let explode str =
let rec explode_inner cur_index chars =
if cur_index < String.length str then
let new_char = str.[cur_index] in
explode_inner (cur_index + 1) (chars @ [new_char])
else chars in
explode_inner 0 []
(* Converts a list of chars to a string *)
let rec implode chars =
match chars with
[] -> ""
| h::t -> string_of_char h^(implode t)
此外,對於下面的解釋:如果在字符串中應編譯器甚至拆分字符串? 「abc」改爲「a」「bc」或「ab」「c」 – 0x434D53 2015-11-25 15:51:21