【问题标题】:OCaml strange behavior in pattern matchingOCaml 模式匹配中的奇怪行为
【发布时间】:2017-10-11 02:23:20
【问题描述】:

我正在尝试在 OCaml 中实现一个队列结构,现在编写一个函数来测试一个值是否在队列中。我最初写了一个正确的——或者至少我认为这是一个正确的——函数的实现。但是当我测试它时,我会遇到意想不到的测试失败。也就是说,当队列为空时它会返回 false(一件好事),但在其他情况下也会返回 false,无论队列是否为空,以及队列是否包含值。所以我以这种愚蠢的方式(Some h -> true)重新编写了函数,以试图找出问题所在。即使使用这个愚蠢的函数,当我将任何队列和任何值传递给它时,它仍然返回 false,因此很明显它会将每个队列的头部读取为 None,无论它是否是 None

包含:

let contains (v: 'a) (q: 'a queue) : bool =
    if not (valid q) then failwith "contains: given invalid queue";
    let rec loop (value: 'a) (qn: 'a qnode option) : bool =
      begin match qn with
      | None -> false
      | Some h -> true
      end
    in loop elt q.head

测试

   let test () : bool =
    let q = create () in
    not (contains 1 q)
  ;; run_test "contains empty" test

  let test () : bool =
    let q = from_list [2; 3] in
    contains 3 q
  ;; run_test "contains non-empty true" test

  let test () : bool =
    let q = from_list [2; 3] in
    not (contains 4 q)
  ;; run_test "contains non-empty false" test

这里写的其他函数已经过测试,按预期出来了。队列类型的类型声明是

  type 'a qnode = { v: 'a;
                    mutable next: 'a qnode option }

  type 'a queue = { mutable head: 'a qnode option;
                     mutable tail: 'a qnode option }

任何关于为什么将每个 q.head 都变成 None 的想法将不胜感激。


from_list

一个帮助函数,它遍历一个列表,将每个值转换为一个 qnode 并将其链接到下一个,返回结果列表。

  let rec vals_to_qnodes (l: 'a list) : 'a qnode list =
    begin match l with
    | [] -> []
    | [h] -> [{v = h; next = None}]
    | h1::h2::t -> let sofar = vals_to_qnodes (h2::t) in
                    begin match sofar with
                    | [] -> []
                    | x::y -> {v = h1; next = Some x}::x::y
                    end
    end

制作qnodes列表,找到它的第一个和最后一个元素,并将它们分配为队列的头和尾。

  let from_list (l: 'a list) : 'a queue =
    let qsList = vals_to_qnodes l in
    begin match qsList with
    | [] -> create ()
    | h::t -> begin match t with
              | [] -> {head = Some h; tail = Some h}
              | h2::t2 -> let x = List.rev t2 in
                          begin match x with
                          | [] -> {head = None; tail = None;}
                          | h3::t3 -> {head = Some h; tail = Some h3}
                          end
              end
    end

在我尝试简化它以缩小奇怪行为之前,这是我最初对 contains 函数所做的。

let contains (v: 'a) (q: 'a queue) : bool = 
  if not (valid q) then failwith "contains: given invalid queue";
  let rec loop (value: 'a) (qn: 'a qnode option) : bool = 
    begin match qn with 
    | None -> false
    | Some h -> if v == value then true 
                else loop value h.next
    end
  in loop v q.head

【问题讨论】:

    标签: pattern-matching ocaml


    【解决方案1】:

    当我尝试您的代码时,它的行为与您描述的不同:

    # let n = { v = 1; next = None };;
    val n : int qnode = {v = 1; next = None}
    # let q = { head = Some n; tail = Some n };;
    val q : int queue =
      {head = Some {v = 1; next = None}; tail = Some {v = 1; next = None}}
    # contains 3 q;;
    - : bool = true
    

    所以,我想说答案取决于 from_list 实际返回的内容。

    作为旁注,您对contains 的定义引用了elt,在我能看到的任何地方都没有定义。

    更新

    您的新代码没有定义create。我为create 提供了这个定义:

    let create () = { head = None; tail = None }
    

    如果我运行from_list [1;2],这就是我看到的:

    # from_list [1;2];;
    - : int queue = {head = None; tail = None}
    

    这可以解释为什么头像是None :-)

    【讨论】:

    • 我会用from_list的内容更新帖子。 contains 函数不使用 elt 值,因为我愚蠢的重写。我还将发布 contains 的原始代码。
    • 函数 from_list 在传递长度为 2 的列表时似乎返回一个空队列。
    猜你喜欢
    • 2011-12-26
    • 1970-01-01
    • 2020-08-21
    • 2013-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多