【问题标题】:Ocaml Pattern Matching QualmsOcaml 模式匹配问题
【发布时间】:2013-08-02 12:14:29
【问题描述】:

我在 Ocaml 中的模式匹配方面遇到了一些问题。

基本上,我需要编写一个名为 reversed 的函数,它接受一个列表并检查它是否按相反的顺序排列。

到目前为止:

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:我理解这种情况,如果我做错了什么,请指出来。

【问题讨论】:

  • 除了已经给出的答案,让我挑剔if y &lt; z then false else E 只是说y &gt;= z &amp;&amp; E 的一种复杂方式。

标签: functional-programming ocaml


【解决方案1】:

你的函数的问题在这里:

| y::z::tl -&gt; if y &lt; z then false else reversed tl;

让我们看看你的列表:[5;4;3;1;2]

这样分解:

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

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

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

| y::z::_ -&gt; if y &lt; z then false else reversed z;

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

| y::z::tl -&gt; if y &lt; z then false else reversed (z::tl)

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

| y::(z::_ as tl) -&gt; if y &lt; 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;;

【讨论】:

    【解决方案2】:

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

    [5;3;4;2;1]
    

    告诉你它正在反转/减少。这是因为你过早地放弃了 3。你的中间子句应该是:

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

    【讨论】:

    • 天哪,没看到。无论如何,[5;4;3;1;2];;似乎现在也可以工作。 y::z::tl 是否已经捕捉到了?
    • @Secret 当然,模式说:一个至少包含 2 个元素的列表
    【解决方案3】:

    你应该使用| y::z::tl -&gt; if y &lt; z then false else reversed (z::tl)

    如果 y > z,则不应将 z 从下一轮列表中删除,因为 z 尚未与下一个项目进行比较。

    你也不需要 ; 在那一行。

    正确的代码是

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

    【讨论】:

      【解决方案4】:

      这是另一种使用模式保护和通配符等其他概念编写它的方法:

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

      这样一来,一种情况为真,一种情况为假,一种情况为递归。

      【讨论】:

      • 大声笑我很尴尬地说我不知道​​“何时”存在,谢谢。这很干净
      猜你喜欢
      • 2011-05-31
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-11
      • 2018-09-18
      • 1970-01-01
      相关资源
      最近更新 更多