Ocaml模式匹配问题

时间:2013-08-02 12:14:29

标签: functional-programming ocaml

我在Ocaml中遇到一些关于模式匹配的问题。

基本上,我需要编写一个名为reverse的函数,它接受一个列表并检查它是否是颠倒的顺序。

到目前为止:

let rec reversed (x:int list):bool =
   match x with
   | [] -> true
   | y::z::tl -> if y < z then false else reversed tl;
   | y::[] -> true;;

有效! (实际上让我惊讶的是:P)但是我看到了一个缺陷,那就是如果没有tl,它将无法匹配。测试此返回true:

  reversed [5;4;3;1;2];;

这是完全可以理解的,因为没有更多的尾巴它只是匹配y :: []

我该如何解决这个问题?

PS:这是我与Ocaml的第一天。对不起,如果问题很简单:D

PPS:我故意只使用Core。 (没有模块)

PPPS:我理解如果我做了一些根本错误的事情,请指出。

4 个答案:

答案 0 :(得分:4)

你的功能问题在于:

| y::z::tl -> if y < z then false else reversed tl;

让我们看看你的清单:[5; 4; 3; 1; 2]

它以这种方式分解:

| 5::4::[3;1;2]

你比较5和4,然后用[3; 2; 1]调用恢复。这意味着4到3之间的比较没有完成!(你可以尝试使用像[5; 4; 99; 98; 97]这样的列表,这是你有意想不到的结果)。

你应该做的是在z上测试,然后用列表的其余部分调用reverted。但是,如果你尝试类似的东西:

| y::z::_ -> if y < z then false else reversed z;

编译器对你大吼大叫,因为z是一个int(而不是int列表)。要解决此问题,您可以通过在tl前面添加z来“重建”列表:

| y::z::tl -> if y < z then false else reversed (z::tl)

或者在y(包含z)之后命名列表,同时仍然提取z:

| y::(z::_ as tl) -> if y < z then false else reversed tl

至于你对这个问题的猜测,我理解你的逻辑,但实际上它并不是那样的。 []可以在分解中“命名”,就像它是一个常规节点一样。

看看这个例子,一个(坏)函数测试是否到达列表的末尾:

let is_end l = match l with | a -> false | [] -> true;;

如果您尝试将其放入口译员,则应收到以下消息: Warning 11: this match case is unused.

那是因为[]已经在第一场比赛中被抓住了。您可以尝试使用is_end [],它会返回false。

处理此问题的正确方法是如何在代码中执行此操作:

let is_end l = match l with | x::_ -> false | [] -> true;;

答案 1 :(得分:2)

您的程序逻辑错误。您想检查列表是否反转(减少?)。但是你的程序输入失败

[5;3;4;2;1]

告诉你它正在逆转/减少。这是因为你太早掉了3。你的中间条款应该是:

   | y::z::tl -> if y < z then false else reversed (z::tl);

答案 2 :(得分:1)

您应该使用| y::z::tl -> if y < z then false else reversed (z::tl)

如果y&gt; z,你不应该从下一轮列表中删除z,因为z尚未与下一个项目进行比较。

此外,您不需要;

正确的代码是

let rec reversed = function
  | [] -> true
  | hd::[] -> true
  | hd1::hd2::tl ->
    if hd1 < hd2 then false
    else reversed (hd2::tl)

答案 3 :(得分:1)

这是另一种使用其他概念来编写它的方法,如图案保护和外卡:

let rec reversed = function
  | [] | [_] -> true
  | hd1::hd2::_ when hd1 < hd2 -> false
  | _::tl -> reversed tl;;

这种情况有一种情况是真的,一种是假的,一种是递归的。