Ocaml - 两个节点之间的路径(如何调试)

时间:2015-09-03 12:18:42

标签: graph path ocaml

我需要使用 BFS 制作一个算法来解决这个问题: 给定一个有向加权图,一个起始节点,一个停止节点和一个整数K,比如说在开始和停止之间是否存在一条至少为k的路径。

所以,首先我宣布了我的加权导向图类型,一个三元组列表:

 type 'a graph = Gr of ('a * 'a * 'a) list;;

 let grafo1 =  Gr [(1,3,2);(1,1,5);(2,2,3);(5,5,3);(5,4,6);(3,1,6);(3,7,4);(6,2,7);(4,4,6)];;

(x,y,z)中,x是起始节点,y是边缘权重,z是到达节点。

然后我做了一个 succ 功能:

let succ (Gr arcs) n=
     let rec aux = function
         [] -> []
         | (x,y,z):: rest ->
           if n = x then z::(aux rest)
           else aux rest 
    in aux arcs;;

这个函数给我一个节点的后继者作为oputput,所以:

succ grafo1 1 

给了我

   int list = [2; 5]

作为输出。

最后,我创建了这个 bf_path 函数,它是一个修改过的BFS,可以找到2个节点之间的路径(否则会引发异常),需要3个输入:图形,谓词和起始节点

 let bf_path g p start =  
       let rec aux visited = function  
           [] -> raise Not_found  
           | x::rest -> if List.mem x visited then aux visited rest  
              else if p x then [x]  
              else try aux (x::visited) rest  
                with Not_found ->  
                  x:: aux (x::visited) (succ g x)  
       in aux [] [start];; 

谓词指定条件,因此调用:

  bf_path grafo1 ((=)7)1

给我int list = [1; 5; 6; 7]作为输出,即节点1和7之间的路径。

现在,我可以找到一条路径,但我需要找到至少权重K的路径,所以我做了一个小函数,它将三元组列表作为输入,它总重量值:

let rec tot = function
   [] -> 0
   |(v,c,p)::t -> c + (tot t);;

所以,呼叫和输出:

  tot [(2,2,3);(4,5,6);(8,9,0)]

   - : int = 16

我认为我需要的是在函数内部添加条件,所以我创建了这个函数,我添加了一个int K作为输入和条件:(tot path >= k)

   let bf_path_final g p start k =  
      let rec aux visited = function  
        [] -> raise Not_found  
        | x::rest -> if List.mem x visited then aux visited rest  
            else if p x then 
               if (tot [x]) >= k then [x]
               else aux visited rest 
            else try aux (x::visited) rest  
              with Not_found ->  
                x:: aux (x::visited) (succ g x)  
      in aux [] [start];; 

该函数编译没有问题:

   val bf_path_final : ('a * int * 'b) graph -> 
  ('a * int * 'b -> bool) -> 'a * int * 'b -> int -> ('a * int * 'b) list = <fun>

但是,当我尝试调用它时,我收到错误

bf_path_final grafo1 ((=)4)1,13;;
              ^^^^^^
Error: This expression has type int graph_w
       but an expression was expected of type ('a * int * 'b) graph_w

那么,函数是错误的还是我必须以另一种方式调用它?

另一个解决方案是将函数 bf_path 输出(路径)作为 tot 函数的输入,但我的输出是一个列表int,而不是三元组列表,所以我试图将我的第一个函数转换为三元组的输出:

(例如:代替[1;5;6;7],它应该提供[(1,1,5);(5,4,6);(6,2,7)]

let bf_path_tr g p start =  
    let rec aux visited = function  
         [] -> raise Not_found  
         | (x,y,z)::rest -> if List.mem x visited then aux visited rest  
            else if p x then [(x,y,z)]  
            else try aux (x::visited) rest  
              with Not_found ->  
                 (x,y,z):: aux (x::visited) (succ_w g (x,y,z))  
    in aux [] [start];; 

结果相同,编译函数

 val bf_path_tr :
  ('a * 'b * 'c) graph ->
  ('a -> bool) -> 'a * 'b * 'c -> ('a * 'b * 'c) list = <fun>

但是我得到了同样的错误:

bf_path_tr grafo1 ((=)7)2

  Characters 11-18:
  bf_path_tr grafo1 ((=)7)2;;
             ^^^^^^
  Error: This expression has type int graph
     but an expression was expected of type ('a * 'b * 'c) graph

要解决这两个问题中的至少一个的任何想法?

1 个答案:

答案 0 :(得分:0)

调试此类事情的最佳方法是开始在任何地方添加显式类型注释,直到找到您的期望与推断类型不匹配的位置。

let bf_path_final (g : int graph) (p : int -> bool) (start : int) (k : int) =   
  let rec aux (visited : int list) = function  
      [] -> raise Not_found  
    | x::rest -> if List.mem x visited then aux visited rest  
      else if p x then ( 
        if (tot [x]) >= k then [x] 
        else aux visited rest )
      else try aux (x::visited) rest  
        with Not_found ->  
          x:: aux (x::visited) (succ g x)  
  in aux [] [start];; 

引发错误

File "test.ml", line 32, characters 17-18:
Error: This expression has type int but an expression was expected of type
         'a * int * 'b

指向if (tot [x]),其中tot确实需要三元组列表,但您已将其传递给了一个int列表。

你真的打电话给tot [x]吗?它不是任何东西; x只是那里的一个节点。