OCaml学习——Configuration-for-merlin
Configuration for merlin
Emacs+Spacemacs+ocaml layer 进行 OCaml 语法学习,刷题过程,调用外部库和自建模块时 Merlin 检测一直报错,并且 auto-completension 也会随之失效。今天在 Merlin Issue 查阅一些信息后,遵循Github Wiki,算是弄明白问题的原因,也了解了.merlin
的配置。
Unbound module XXX
正确安装并加载tuareg-mode
(提供语法高亮)以及merlin-mode
后,Merlin 每次在C-x C-s
保存时检查错误,比如在一个factorial
目录中,我们创建了factorial.ml
和test.ml
文件。
factorial.ml
模块内包含一个计算累乘的函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26let factorial =
(* Because we have a closure, `ht` persists across calls to `factorial`. *)
let ht = ref (Hashtbl.create 100) in
let _ = Hashtbl.add (!ht) 0 (Big_int.big_int_of_int 1) in
let max = ref 1 in
fun (n:int) ->
if n < 0 then
failwith "n < 0"
else
let ht = !ht in
try
(* Check if `ht` contains the value of `factorial n`. Return it
if so. *)
Hashtbl.find ht n
with Not_found ->
let rec aux i n =
let x = Big_int.mult_int_big_int i (Hashtbl.find ht (i - 1)) in
if i = n then
x
else
let () = Hashtbl.add ht i x in
aux (i + 1) n in
let result = aux !max n in
(* Update `max`, and return the `result`. *)
let _ = max := n in
resulttest.ml
用于单元测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31open Big_int
open Factorial
open OUnit2
let () = run_test_tt_main ("factorial n" >::: [
"n < 0" >:: (fun _ ->
assert_raises (Failure "n < 0") (fun () -> factorial (-1))
);
"n = 0" >:: (fun _ ->
assert (eq_big_int (big_int_of_int 1) (factorial 0))
);
"n = 1" >:: (fun _ ->
assert (eq_big_int (big_int_of_int 1) (factorial 1))
);
"n = 2" >:: (fun _ ->
assert (eq_big_int (big_int_of_int 2) (factorial 2))
);
"n = 3" >:: (fun _ ->
assert (eq_big_int (big_int_of_int 6) (factorial 3))
);
"n = 10" >:: (fun _ ->
assert (eq_big_int (big_int_of_int 3628800) (factorial 10))
);
])
我们发现,虽然顶层环境中可以进行简单的函数测试,但是保存test.ml
时 Merlin 检测每次都会报如下错误,自动检测也随之失效了。
1 |
|
而实际上,我们已经通过opam install ounit2
安装了 OUnit2,并且构造完成 Factorial 模块,只是 Merlin 没有感知到。merlin 只能感知到编译完成的文件(严格地说应该是编译好接口)的文件,所以多文件(模块)下,没有编译时 Merlin 就会报 Error
Configuration for .merlin
files
ocamlbuild xxx.cmi
编译自己编写的模块,然后C-c C-f <RET> .merlin
编辑.merlin
配置文件如下。
1 |
|
简单说一下.merlin
文件的配置规则,更完整的文件配置见Merlin Wiki Project configuration
S: Source path
S
指定目录让 Merlin 感知到其他源文件。如果项目文件分布在不同文件中,使用S
来告知 Merlin。B: Build path
B
为了让 Merlin 能够从其他文件来提供 type of identifiers 以及补全,它需要知道在哪里可以找到项目的其他模块的.cmi
文件(这也是本文解决的点)。PKG: Packages
如果使用了外部库,需要 findlib package,我们只需要在
.merlin
中添加 PKG,比如ounit2
,需要小写(与传递给ocamlfind
保持一致)。
Basic call
一些 Emacs 编辑.ml
文件常用的快捷键
C-c C-e
tuareg-eval-phrase 传递语句到终端(OCaml 顶层环境),最常用C-c C-t
merlin-type-enclosing 类型查询(配合C-
和上下方向键控制包括区域)C-c C-x
merlin-error-next 下一个 errorC-c [
: ocaml-open-module 打开模块C-c ]
: ocaml-close-module 关闭模块
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!