Functional programming 在OCaml中实现就地图BFS时出现奇怪的错误

Functional programming 在OCaml中实现就地图BFS时出现奇怪的错误,functional-programming,ocaml,Functional Programming,Ocaml,我正在OCaml中实现就地图形BFS 这是我的密码: type graph = {s : int list array;num_v:int;mutable num_e : int};; let bfs u g p = let marker = Array.make g.num_v false in let q = Queue.create() in Queue.push u q; let rec add_to_queue v = function | [] -

我正在OCaml中实现
就地图形BFS

这是我的密码:

type graph = {s : int list array;num_v:int;mutable num_e : int};;

let bfs u g p =
  let marker = Array.make g.num_v false
  in
  let q = Queue.create()
  in 
  Queue.push u q;
  let rec add_to_queue v = function
    | [] -> ()
    | hd::tl -> 
      if not marker.(hd) then begin
        marker.(hd) <- true;
        Queue.push hd q;
        p.(hd) <- v
      end; 
      add_to_queue v tl
  in 
  **let rec bfs_go =**
    if Queue.length q > 0 then begin
      let v = Queue.pop q
      in 
      print_int v;
      add_to_queue v g.s.(v);
      bfs_go
    end 
  in 
  bfs_go;;
你可能是说

let rec bfs_go () =
  ...;
  bfs_go ()
而不是

let rec bfs_go =
   ...;
   bfs_go
编辑:我无法抗拒一些改进

你的命令式风格:

let bfs start graph from =
  let marker = Array.make graph.num_v false in
  let q = Queue.create() in 
  let add_to_queue parent node =
    if not marker.(node) then begin
      marker.(node) <- true;
      Queue.push node q;
      from.(node) <- parent;
    end in
  Queue.push start q;
  while not (Queue.is_empty q) do
    let node = Queue.pop q in 
    print_int node;
    List.iter (add_to_queue node) graph.s.(node)
  done
让bfs从=
让marker=Array.make graph.num\u v在中为false
让q=队列中的Queue.create()
让我们将\u添加到\u队列父节点=
如果不是标记。(节点),则开始
标记。(节点)bfs next[]
|节点::当前,下一个->
让我们接下来添加父节点=
如果是标记。(节点),则为下一步
否则开始
标记(节点)
打印节点;
让孩子=
中的List.filter(趣味儿童->非标记(儿童))g.s.(节点)
iter(有趣的孩子->标记器(孩子)你可能是指

let rec bfs_go () =
  ...;
  bfs_go ()
而不是

let rec bfs_go =
   ...;
   bfs_go
编辑:我无法抗拒一些改进

你的命令式风格:

let bfs start graph from =
  let marker = Array.make graph.num_v false in
  let q = Queue.create() in 
  let add_to_queue parent node =
    if not marker.(node) then begin
      marker.(node) <- true;
      Queue.push node q;
      from.(node) <- parent;
    end in
  Queue.push start q;
  while not (Queue.is_empty q) do
    let node = Queue.pop q in 
    print_int node;
    List.iter (add_to_queue node) graph.s.(node)
  done
让bfs从=
让marker=Array.make graph.num\u v在中为false
让q=队列中的Queue.create()
让我们将\u添加到\u队列父节点=
如果不是标记。(节点),则开始
标记。(节点)bfs next[]
|节点::当前,下一个->
让我们接下来添加父节点=
如果是标记。(节点),则为下一步
否则开始
标记(节点)
打印节点;
让孩子=
中的List.filter(趣味儿童->非标记(儿童))g.s.(节点)

顺便问一下,我真的应该为OCaml/FPL使用循环吗?@JacksonTale当它们导致简洁优雅的代码时,你应该使用它。在这种情况下,我认为递归对
没有任何好处。在一般情况下,循环的问题是它们迫使你使用副作用(通常是坏的)在您的实现中,我是否可以将您的
[],(\u::\ uAS next)->bfs next[]
更改为
[],next->bfs next[]
?此外,我使用的任何差异都是
列表。左折
而不是
列表。右折
左折
右折
将以不同的顺序累积值,遍历仍将是BFS,但相同级别的节点以不同的顺序遍历。事实上,我使用两个列表而不是一个队列的方式,没有反转
next
意味着我已经更改了与您的代码相关的顺序,因此
列表。向左折叠实际上会更好。关于
(::uu作为next)
,我个人更喜欢它,因为它使模式不重叠,因此通过重新排序得以保留;在代码中,如果您切换前两个子句,它会改变语义。但这也是一个合理的选择。顺便问一下,我真的应该为OCaml/FPL使用loop吗?@JacksonTale当它们导致简洁优雅的代码时,您应该这样做在一般情况下,循环的问题是它们迫使你使用副作用(通常是不好的),但在这里你还是有副作用的,所以没有什么理由不这样做。在你的实现中,我可以把你的
[],(::u.as next)->bfs next[]改成
[],next->bfs next[]
?此外,我使用的任何差异都是
列表。左折
而不是
列表。右折
左折
右折
将以不同的顺序累积值,遍历仍将是BFS,但相同级别的节点以不同的顺序遍历。事实上,我使用两个列表而不是一个队列的方式,没有反转
next
意味着我已经更改了与您的代码相关的顺序,因此
列表。向左折叠实际上会更好。关于
(::uu作为next)
,我个人更喜欢它,因为它使模式不重叠,因此可以通过重新排序来保留;在代码中,如果切换前两个子句,它会改变语义。但这也是一个合理的选择。
let dfs u g p =
  let marker = Array.make g.num_v false in
  let rec dfs_go node =
    print_int node;
    let go_child child =
      if not marker.(child) then begin
        marker.(child) <- true;
        dfs_go child;
      end in
    List.iter go_child g.s.(node)
  in 
  marker.(u) <- true;
  dfs_go u;;