【问题标题】:Ocaml and return type (graph theory)Ocaml 和返回类型(图论)
【发布时间】:2018-11-22 22:29:34
【问题描述】:

我只是 Ocaml 的初学者,我想研究图论,但在 Ocaml 中实现。而且我在做某事时遇到了麻烦:我只是想通过使用深度优先搜索来列出图形的连接组件。所以,我做到了:

#open "stack" ;;

let non_empty pile = 
    try push (pop pile) pile ; true with Empty -> false ;;


let connected_comp g = 
    let already_seen = make_vect (vect_length g) false in
    let comp = [] in

    let dfs s lst = 
        let totreat = new () in
        already_seen.(s) <- true; push s totreat;

        let rec add_neighbour l = match l with
            | [] -> ()
            | q::r when already_seen.(q) = false -> push q totreat; already_seen.(q) <- true; add_neighbour r
            | q::r -> add_neighbour r
        in

        while non_empty totreat do
            let s = pop totreat in
            already_seen.(s) <- true;
            (* we want to add s to the list lst *) s::lst;
            add_neighbour g.(s);
        done
    in  


    let rec head_list l = match l with
        | [] -> failwith "Empty list"
        | p::q -> p
    in  
    let rec aux comp t = match t with
        | t when t = vect_length g -> comp
        | t when already_seen.(t) = true -> aux comp (t+1)
        | t -> aux ((dfs t [])::comp) (t+1) (* we want that dfs t [] return the list lst modified *)
    in aux comp 0;;

我得到:

>       | t -> (dfs t [])::comp ; aux  comp (t+1) (* we want that dfs t [] return the list lst modified *)
>              ^^^^^^^^^^^^^^^^
Warning : this expression is of type unit list,
but is used with the type unit.
connected_comp : int list vect -> unit list = <fun>
- : unit list = []
- : unit = ()

当然,我并不感到惊讶。但我想要做的是函数dfs 返回在参数上发送的列表(lst 列表)但已修改,这里不是这种情况,因为函数是单元类型,因为它什么都不返回。但是在 Ocaml 中,由于语言是为返回我认为的最后一个表达式而设计的,我不知道该怎么做。我也可以对dfs 函数使用递归算法,因为通过过滤,它允许我返回列表,但我只是想了解 Ocaml,因此修改(即使它不是最优的)我的算法。

有人可以帮帮我吗?

编辑:正如我们问我的那样,我会尽量减少我的代码并直奔主题。所以,我有函数 dfs 对应于深度优先搜索(用于图形)

let dfs s lst = 
    let totreat = new () in
    already_seen.(s) <- true; push s totreat;

    let rec add_neighbour l = match l with
        | [] -> ()
        | q::r when already_seen.(q) = false -> push q totreat; already_seen.(q) <- true; add_neighbour r
        | q::r -> add_neighbour r
    in

    while non_empty totreat do
        let s = pop totreat in
        already_seen.(s) <- true;
        (* we want to add s to the list lst *) s::lst;
        add_neighbour g.(s);
    done
in

(alreadyseen是一个布尔向量,之前定义过)

我唯一的问题是我希望函数返回列表 lst 修改后(在循环中),此时它是一个单位函数。

我试图将 lst 定义为引用,但后来我不知道如何返回它...

我希望它更清楚,我目前对这一切都不熟悉......

谢谢!

【问题讨论】:

  • 尝试编写只包含dfs 定义且不依赖外部数据类型的代码的最小版本。这将使我们更容易为您提供帮助。另请注意,如果您想“了解 OCaml”,那么学习编写递归函数并避免副作用是重点。
  • 请注意,代码示例是在 Caml Light 中而不是在 OCaml 中。

标签: ocaml graph-theory return-type


【解决方案1】:

这是您的代码的降级版本,它演示了一种实现您想要的方式的方法。

let non_empty _ = false

let dfs s lst =
  let local_lst = ref lst in

  while non_empty () do
    (*do stuff here*)
    let s = 1 in
    local_lst := s::!local_lst;
    (*do stuff here*)
  done;
  !local_lst

我首先将一个本地可变值local_lst 初始化为作为参数给出的列表lst。然后我在while 循环中更新这个值。最后我返回存储在local_lst 中的值。

【讨论】:

  • 简直完美,非常感谢!是否也有可能要求函数 dfs 的第一个参数作为参考以直接修改它并在最后返回它?无论如何,非常感谢!
  • 是的,lst 可以作为参考,如果这样做,最后不需要返回它,因为参考会被修改。然后,函数的返回类型将是unit,您可以重用您作为参数提供的引用。
  • 非常感谢您的所有解释! :)
  • 但是使用引用确实不是 ocaml 的方式。通常在函数式语言中,您返回新值而不是修改任何内容。
  • @GoswinvonBrederlow 是对的。你应该学会不使用可变值,你会很快看到好处,因为调试变得容易得多。
猜你喜欢
  • 2019-04-11
  • 2014-01-02
  • 2014-03-01
  • 2021-03-11
  • 2011-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多