顶级 Ocaml 无限解释循环
Toplevel Ocaml infinit interpretation loop
这段代码不会输出语法错误,但也不会结束编译。当我注释 toutes_reponses
函数时,代码将编译并执行。 toutes_reponses
运行 是否处于一种无限解释器循环中?
我用ocaml
和#use "code.ml"
编译。
此外,CPU 在此期间 运行 处于 100%。
#load "str.cma";;
module Code:
sig
(** Le type d'un pion *)
type pion = string
(** Le type d'un code *)
type t = pion list
(** Le nombre de pions par code*)
val nombre_pion : int
(** Le nombre de couleur et symboles possibles*)
val couleur_possibles : pion list
(** Compare deux codes
* @param code1 premier code a comparer
* @param code2 second code a comparer
* @return 0 si les deux codes sont identiques,
un entier positif si [code1] est strictement plus grand que [code2]
un entier negatif si [code1] est strictement plus petit que [code2]
*)
val compare : t -> t -> int
(** Conversion chaine de caracteres vers code (pour saisie)
* @param string chaine de caractere saisie
* @return le code correspondant a la saisie si la conversion est possible
[None] si la conversion n'est pas possible
*)
val string_of_code : t -> string
(** Conversion chaine de caracteres vers code (pour saisie)
* @param string chaine de caractere saisie
* @return le code correspondant a la saisie si la conversion est possible
[None] si la conversion n'est pas possible
*)
val code_of_string : string -> t
(** La liste de tous les codes permis *)
val tous : t list
(** La liste de toutes les reponses possibles *)
val toutes_reponses : (int * int) list
(** Calcule la reponse d'un code par rapport au code cache
* @param code le code propose
* @param vrai_code le code cache
* @return un couple (nombre de pions bien places, nombre de pions mal places)
[None] si la reponse ne peut etre calculee
*)
val reponse : t -> t -> (int * int)
val convert : int -> int -> int -> int list -> int list
val finirTableau : int -> int list -> int list
end = struct
type pion = string;;
type t = pion list;;
let nombre_pion = 4;;
let couleur_possibles = ["Rouge"; "Vert"; "Bleu"; "Orange"; "Noir"; "Blanc"];;
let compare code1 code2 =
match (code1, code2) with
| a::b, c::d -> (if a = c then compare b d else
if a > c then 1 else -1)
| _, _ -> 0;;
let string_of_code code = List.fold_right (fun x y -> x ^ "_" ^ y) code "";;
let code_of_string code = List.filter (fun x -> String.length x != 0) (Str.split_delim (Str.regexp "_") code);;
let rec convert x b i tmp =
if x = 0 then tmp
else convert (x / b) b (i + 1) tmp @ [x mod b];;
let rec finirTableau b tab =
if (List.length tab) = b then tab
else finirTableau b (tab @ [0]);;
let tous =
let n = List.length couleur_possibles and m = nombre_pion in
let rec aux i acc =
if i = -1 then acc else aux (i - 1) acc @ [(List.map (fun x -> (List.nth couleur_possibles x))(finirTableau m (convert i n 0 [])))];
in aux (int_of_float ((float_of_int n) ** (float_of_int m)) - 1) [];;
let toutes_reponses =
let m = nombre_pion in
let rec aux i acc =
let array = finirTableau 2 (convert i m 0 []) in
if i = -1 then acc else aux (i - 1) (acc @ [(List.nth array 0, List.nth array 1)]);
in aux (nombre_pion * nombre_pion) [];;
let reponse code secret = (1,2);;
end;;
您的代码编译得很好,它只是 运行 进入 tous
之前的函数之一的无限循环。要调试此问题,您可以先添加 assert 语句来记录递归函数的入口条件。
另请注意,您的代码中存在许多低效之处,您应避免:
List.nth
(如果你需要随机访问,你应该使用的数据结构是_ array
)
- 附加在列表的末尾(例如
tab @ [0]
)。一般来说,@
左侧的列表应该很小。
- 在递归函数中调用
List.length
同样,如果你想在一个字符上拆分字符串,标准库中有String.spilt_on_char
(因为OCaml ≥4.04)。
toutes_reponses
的类型是
toutes_reponses : (int * int) list
在解释器中加载您的文件会导致对所有声明的条款进行评估,包括这一条款。显然你陷入了它的评估。如果你希望能够在解释器中加载文件,把它变成一个暂停的计算,
toutes_reponses : unit -> (int * int) list
let toutes_reponses () = ...
这段代码不会输出语法错误,但也不会结束编译。当我注释 toutes_reponses
函数时,代码将编译并执行。 toutes_reponses
运行 是否处于一种无限解释器循环中?
我用ocaml
和#use "code.ml"
编译。
此外,CPU 在此期间 运行 处于 100%。
#load "str.cma";;
module Code:
sig
(** Le type d'un pion *)
type pion = string
(** Le type d'un code *)
type t = pion list
(** Le nombre de pions par code*)
val nombre_pion : int
(** Le nombre de couleur et symboles possibles*)
val couleur_possibles : pion list
(** Compare deux codes
* @param code1 premier code a comparer
* @param code2 second code a comparer
* @return 0 si les deux codes sont identiques,
un entier positif si [code1] est strictement plus grand que [code2]
un entier negatif si [code1] est strictement plus petit que [code2]
*)
val compare : t -> t -> int
(** Conversion chaine de caracteres vers code (pour saisie)
* @param string chaine de caractere saisie
* @return le code correspondant a la saisie si la conversion est possible
[None] si la conversion n'est pas possible
*)
val string_of_code : t -> string
(** Conversion chaine de caracteres vers code (pour saisie)
* @param string chaine de caractere saisie
* @return le code correspondant a la saisie si la conversion est possible
[None] si la conversion n'est pas possible
*)
val code_of_string : string -> t
(** La liste de tous les codes permis *)
val tous : t list
(** La liste de toutes les reponses possibles *)
val toutes_reponses : (int * int) list
(** Calcule la reponse d'un code par rapport au code cache
* @param code le code propose
* @param vrai_code le code cache
* @return un couple (nombre de pions bien places, nombre de pions mal places)
[None] si la reponse ne peut etre calculee
*)
val reponse : t -> t -> (int * int)
val convert : int -> int -> int -> int list -> int list
val finirTableau : int -> int list -> int list
end = struct
type pion = string;;
type t = pion list;;
let nombre_pion = 4;;
let couleur_possibles = ["Rouge"; "Vert"; "Bleu"; "Orange"; "Noir"; "Blanc"];;
let compare code1 code2 =
match (code1, code2) with
| a::b, c::d -> (if a = c then compare b d else
if a > c then 1 else -1)
| _, _ -> 0;;
let string_of_code code = List.fold_right (fun x y -> x ^ "_" ^ y) code "";;
let code_of_string code = List.filter (fun x -> String.length x != 0) (Str.split_delim (Str.regexp "_") code);;
let rec convert x b i tmp =
if x = 0 then tmp
else convert (x / b) b (i + 1) tmp @ [x mod b];;
let rec finirTableau b tab =
if (List.length tab) = b then tab
else finirTableau b (tab @ [0]);;
let tous =
let n = List.length couleur_possibles and m = nombre_pion in
let rec aux i acc =
if i = -1 then acc else aux (i - 1) acc @ [(List.map (fun x -> (List.nth couleur_possibles x))(finirTableau m (convert i n 0 [])))];
in aux (int_of_float ((float_of_int n) ** (float_of_int m)) - 1) [];;
let toutes_reponses =
let m = nombre_pion in
let rec aux i acc =
let array = finirTableau 2 (convert i m 0 []) in
if i = -1 then acc else aux (i - 1) (acc @ [(List.nth array 0, List.nth array 1)]);
in aux (nombre_pion * nombre_pion) [];;
let reponse code secret = (1,2);;
end;;
您的代码编译得很好,它只是 运行 进入 tous
之前的函数之一的无限循环。要调试此问题,您可以先添加 assert 语句来记录递归函数的入口条件。
另请注意,您的代码中存在许多低效之处,您应避免:
List.nth
(如果你需要随机访问,你应该使用的数据结构是_ array
)- 附加在列表的末尾(例如
tab @ [0]
)。一般来说,@
左侧的列表应该很小。 - 在递归函数中调用
List.length
同样,如果你想在一个字符上拆分字符串,标准库中有String.spilt_on_char
(因为OCaml ≥4.04)。
toutes_reponses
的类型是
toutes_reponses : (int * int) list
在解释器中加载您的文件会导致对所有声明的条款进行评估,包括这一条款。显然你陷入了它的评估。如果你希望能够在解释器中加载文件,把它变成一个暂停的计算,
toutes_reponses : unit -> (int * int) list
let toutes_reponses () = ...