为什么这个 OCaml 代码会导致运行时错误?

时间:2021-03-29 02:30:35

标签: ocaml

我正在尝试在编码问题网站上运行以下代码,它说存在运行时错误,但在顶级 ocaml 上运行它似乎工作正常。代码中是否有任何错误来源?提前致谢

问题是在给定的列表中找到“好段”的数量和一个特定的数字。一个好的段定义如下:

  1. A 和 B 是正整数,使得 A < B。
  2. 满足 A <= x <= B 的 x 不是给定列表的元素。

以下是输入。

  1. n,这是列表中将要给出的元素数。
  2. a, b, c, ... 它们是列表的元素。
  3. t,这是段中必须包含的数字。

输出应该是打印出来的单个数字。

编辑代码:

let rec drop_value l to_drop =
  match l with
  | [] -> []
  | hd :: tl ->
    let new_tl = drop_value tl to_drop in
    if hd = to_drop then new_tl else hd :: new_tl
;;

let rec find_start li t cur_min =
  match li with
  | [] -> cur_min
  | hd :: tl -> let new_min = abs (t - hd) in 
  if new_min = 0 then find_start tl t new_min 
  else if new_min < cur_min && t > hd then find_start tl t new_min 
  else find_start tl t cur_min
;;

let rec find_end li t cur_min =
  match li with
  | [] -> cur_min
  | hd :: tl -> let new_min = abs (t - hd) in 
  if new_min = 0 then find_end tl t new_min 
  else if new_min < cur_min && t < hd then find_end tl t new_min 
  else find_end tl t cur_min
;;

let rec contains_value l value =
  match l with
  | [] -> false
  | hd :: tl -> if hd = value then true else contains_value tl value
;;

let nums = ref [];;
let n = read_int () in
for i = 1 to n do
  Scanf.scanf " %d" (fun a -> 
    nums := a :: !nums)
done;

Scanf.scanf " %d" (fun t ->
  if contains_value !nums t then print_int 0
  else let start = if List.length !nums = 1 then 1 else abs (find_start !nums t 1001 - t) in 
  let finish = find_end (drop_value !nums start) t 1001 + t in
  if t > start && t < finish then (if start = 1 && List.length ! nums = 1 then print_int ((t - start + 1) * (finish - t) - 1) else print_int ((t - start) * (finish - t) - 1)) 
  else let start = 1 in print_int ((t - start + 1) * (finish - t) - 1))
;;

例如

5

4 8 13 24 30

10

应该给

5

=> [9, 10], [9, 11], [9, 12], [10, 11], [10, 12]

1 个答案:

答案 0 :(得分:1)

您没有描述您的代码将获得的确切输入格式。这使得调试代码几乎不可能。

当我使用您描述的输入编译并运行您的代码(如 m.ml)时,我看到:

$ ./m
5 4 8 13 24 30 10
Fatal error: exception Failure("int_of_string")

事实上,无论我尝试输入什么格式,我都会得到相同的结果。

这可能就是网站上正在发生的事情。

根据我的经验,使用 scanf 总是弊大于利。将其与其他输入函数结合使用可能会使情况变得更糟。

如果您仔细描述了输入的预期格式,StackOverflow 上的某个人可以推荐一种获取数字的方法。

与此同时,这里有一种方法可以读取一行中的所有数字:

 let rec split_at list n =
     if n = 0 then
         ([], list)
     else
        match list with
        | [] -> ([], [])
        | h :: t ->
            let (a, b) = split_at t (n - 1) in (h :: a, b)
 in

 let (nums, t) =
 let line = read_line () in
 let nstrs = Str.split (Str.regexp "[ \t][ \t]*") line in
 match List.map int_of_string nstrs with
 | [] -> failwith "no numbers"
 | n :: rest ->
      if List.length rest <> n + 1 then
          failwith "bad count"
      else
          let (nums, tlist) = split_at rest n in
          (nums, List.hd tlist)
in
. . .