2012-03-06 78 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