2012-03-06 73 views
4

我是OCaml的新手,試圖將List.append作爲學習練習。這是我有:List.rev表現奇怪嗎?

let rec append a b = 
    match (List.rev a) with 
     []  -> b 
     | x:: xs -> append xs (x::b) 

這似乎是工作,直到說法a有兩個以上的元素。例如:

# append [1;2] [3;4] 
- : int list = [1; 2; 3; 4] 
# append [1;2;3] [4;5;6] 
- : int list = [2; 1; 3; 4; 5; 6] 

這是怎麼回事嗎?我查過了,List.rev [1;2;3]返回int list = [3; 2; 1]。我知道我的實現是天真的,而不是懶惰的,但它似乎應該工作。

+0

你使用'ocamldebug'調試器嗎?你是否查看了* Ocaml *(在'ocaml-3.12/stdlib/list.ml'中)代碼爲'List.rev'的源代碼[free as in speech]? – 2012-03-06 19:23:17

+0

我現在在調試器中,但沒有看到任何明顯的線索。我確實查看了源代碼並確信自己「List.rev」的實現應該像我期望的那樣工作。你有其他想法嗎? – Pygmalion 2012-03-06 19:30:35

+0

在你的'append'或一些打印內容的開始處放置一個斷點。 – 2012-03-06 19:34:01

回答

11

如果你仔細想想,你會顛倒你的第一個列表好幾次。可能比你想要的要多。

如果您按照示例的步驟操作,則可以看到發生了什麼。

append [1; 2; 3] [] 
(* match binds x to 3, xs to [2; 1] *) 
append [2; 1] [3] 
(* match binds x to 1, xs to [2] *) 
append [2] [1; 3] 
(* match binds x to 2, xs to [] *) 
append [] [2; 1; 3] 
(* done *) 
+0

啊啊!我多愚蠢!所以一個正確的版本會有兩個函數'rev_append'和'append',其中'append a b'就是'rev_append(List.rev a)b'。 – Pygmalion 2012-03-06 19:38:27

+0

這會工作,但它是小華麗的! pervasives.ml中的實現更簡單(但不是尾遞歸)。由於這是對你的練習,我不會因爲我自己的實現而給你帶來負擔。 – 2012-03-06 19:43:16

+1

呵呵,雙呃......我可以只是不反轉列表,併爲第二個模式執行'x :: xs - > x :: append xs b'。 – Pygmalion 2012-03-06 19:49:09