是否可以将一组递归函数拆分为OCaml中的2个文件?

时间:2016-04-21 17:10:24

标签: recursion makefile ocaml

我有一个非常长的文件,其中包含一组递归函数。递归是必要的,代码也是有效的。但我只想将文件拆分为2个或更多文件以提高可读性。但我不知道如何在OCaml中分割let rec ... and ... ...

有没有人知道OCaml是否提供了任何机制(例如,指定接口或写makefile的方法)?

非常长的文件可能如下所示:

let rec f1 () =
  ...
  f7 (); (* f7 is called only once by all the functions in the file *)
  f2 ();
  ...
and f2 () =
  ...
  f1 ();
...
and f7 () =
  ...
  f1 (); 
  ...

2 个答案:

答案 0 :(得分:3)

有一种方法:相互递归的仿函数。请参阅this关于OCaml中单独编译的精彩文章和提供主要想法的this鼓舞人心的文章。

这是一个例子。我创建了4个界面mli文件:

$ ls *.mli
Make_moduleA.mli  Make_moduleB.mli  ModuleA.mli  ModuleB.mli

和3个实施文件:

$ ls *.ml
Make_moduleA.ml  Make_moduleB.ml  main.ml

这是界面文件的内容:

(* ModuleA.mli *)
module type ModuleA = sig
   val fa : int -> unit
end

(* ModuleB.mli *)
module type ModuleB = sig
   val fb : int -> unit
end

(* Make_moduleA.mli *)
open ModuleA
open ModuleB
module type Make_moduleA_sig =
  functor (Mb : ModuleB) ->
    sig
      val fa : int -> unit
    end
module Make_moduleA : Make_moduleA_sig

(* Make_moduleB.mli *)
open ModuleA
open ModuleB
module type Make_moduleB_sig =
  functor (Ma : ModuleA) ->
    sig
      val fb : int -> unit
    end
module Make_moduleB : Make_moduleB_sig

相互递归的仿函数:

(* Make_moduleA.ml *)
open ModuleA
open ModuleB    
module type Make_moduleA_sig =
  functor (Mb : ModuleB) ->
    sig
      val fa : int -> unit
    end
module Make_moduleA_impl =
  functor (Mb : ModuleB) ->
    struct
      let rec fa (n : int) =
        if n > 0 then
          (Printf.printf "A: %d\n" n;
           Mb.fb (n - 1))
    end
module Make_moduleA = (Make_moduleA_impl : Make_moduleA_sig)

(* Make_moduleB.ml *)
open ModuleA
open ModuleB    
module type Make_moduleB_sig =
  functor (Ma : ModuleA) ->
    sig
      val fb : int -> unit
    end    
module Make_moduleB_impl =
  functor (Ma : ModuleA) ->
    struct
      let rec fb (n : int) =
        if n > 0 then
          (Printf.printf "B: %d\n" n;
           Ma.fa (n - 1))
    end    
module Make_moduleB = (Make_moduleB_impl : Make_moduleB_sig)

现在让我们结合模块:

(* main.ml *)
open ModuleA
open ModuleB
open Make_moduleA
open Make_moduleB

module rec MAimpl : ModuleA = Make_moduleA(MBimpl)
and MBimpl : ModuleB = Make_moduleB(MAimpl)

let _ =     (* just a small test *)
  MAimpl.fa 4;
  print_endline "--------------";
  MBimpl.fb 4

构建命令序列:

ocamlc -c ModuleA.mli
ocamlc -c ModuleB.mli
ocamlc -c Make_moduleA.mli
ocamlc -c Make_moduleB.mli

ocamlc -c Make_moduleA.ml
ocamlc -c Make_moduleB.ml
ocamlc -c main.ml

ocamlc Make_moduleA.cmo Make_moduleB.cmo main.cmo

测试结果:

$ build.sh && ./a.out
A: 4
B: 3
A: 2
B: 1
--------------
B: 4
A: 3
B: 2
A: 1

答案 1 :(得分:2)

仅供参考,还有另一种方法,没有仿函数。您必须将来自其他模块的函数作为函数的参数。示例:我们以递归方式定义了evenodd,但我们希望even位于模块A中,而odd位于模块{{1}中}}

第一档:

B

第二档:

(* A.ml *)
let rec even odd n =  
  if n=0
  then true
  else 
    if n=1 
    then false
    else (odd even) (n-1) ;;

第三档:

(* B.ml *)
let rec odd even n =  
if n=1
  then true
  else 
    if n=0 
    then false
    else even odd (n-1) ;;

编译(您必须使用选项(* C.ml *) let even = A.even B.odd and odd = B.odd A.even ;; print_endline (if even 5 then "TRUE" else "FALSE") ;; print_endline (if odd 5 then "TRUE" else "FALSE") ;; ):

-rectypes

我不确定我会推荐它,但它确实有效。