OCaml开发环境搭建

去年之前撰文 Haskell开发环境搭建,并且更新了对于VS Code的配置。虽然个人对Vim对使用时间更长,但是对于函数式语言对开发来说,还是觉得Emacs更好上手,特别是交互式开发模式。这一点不论Haskell还是Ocaml都是一样的。

Emacs for OCaml

因为有了Haskell的配置经验,而OCaml的开发环境比Haskell简单不少,所以这里不做太多长篇大论的描述,主要配置参考了Real World OCaml

完整的配置文档

先装依赖:

1
2
3
4
$ brew install opam
$ opam install core utop
$ opam install async yojson core_extended core_bench cohttp async_graphics cryptokit menhir
$ opam install merlin ocp-indent

而后是完整文档,完整快捷键配置需参考注释,常用如下:

  • M-x utop 打开Utop
  • C-c C-t 显示光标所在位置的类型
  • C-c C-l 去到定义处
  • C-c <left> 类型展开/收缩
  • C-c <right> 类型展开/收缩
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
31
32
33
34
35
36
37
38
39
40
41
42
43
;; install OCaml support
(package-install 'tuareg)
(package-install 'utop)
(package-install 'merlin)
(package-install 'auto-complete)

(add-hook 'tuareg-mode-hook 'tuareg-imenu-set-imenu)
(setq auto-mode-alist
(append '(("\\.ml[ily]?$" . tuareg-mode)
("\\.topml$" . tuareg-mode))
auto-mode-alist))
(autoload 'utop-setup-ocaml-buffer "utop" "Toplevel for OCaml" t)
(add-hook 'tuareg-mode-hook 'utop-setup-ocaml-buffer)
(add-hook 'tuareg-mode-hook 'merlin-mode)
(setq merlin-use-auto-complete-mode t)
(setq merlin-error-after-save nil)

;; -- merlin setup ---------------------------------------

(setq opam-share (substring (shell-command-to-string "opam config var share") 0 -1))
(add-to-list 'load-path (concat opam-share "/emacs/site-lisp"))
(require 'merlin)

;; Enable Merlin for ML buffers
(add-hook 'tuareg-mode-hook 'merlin-mode)

;; So you can do it on a mac, where `C-<up>` and `C-<down>` are used
;; by spaces.
(define-key merlin-mode-map
(kbd "C-c <left>") 'merlin-type-enclosing-go-up)
(define-key merlin-mode-map
(kbd "C-c <right>") 'merlin-type-enclosing-go-down)
(set-face-background 'merlin-type-face "#88FF44")

;; -- enable auto-complete -------------------------------
;; Not required, but useful along with merlin-mode
(require 'auto-complete)
(add-hook 'tuareg-mode-hook 'auto-complete-mode)
(setq merlin-ac-setup 't)

;; Replace tuareg by ocp-indent
(setq opam-share (substring (shell-command-to-string "opam config var share") 0 -1))
(load-file (concat opam-share "/emacs/site-lisp/ocp-indent.el"))

Vim for OCaml

Vim中的配置如下,主要依赖Omni和Merlin这个神器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
" Vim needs to be built with Python scripting support, and must be
" able to find Merlin's executable on PATH.
if executable('ocamlmerlin') && has('python')
let s:ocamlmerlin = substitute(system('opam config var share'), '\n$', '', '''') . "/merlin"
execute "set rtp+=".s:ocamlmerlin."/vim"
execute "set rtp+=".s:ocamlmerlin."/vimbufsync"
endif

let g:opamshare = substitute(system('opam config var share'),'\n$','','''')
execute "set rtp+=" . g:opamshare . "/merlin/vim"

if !exists('g:neocomplcache_force_omni_patterns')
let g:neocomplcache_force_omni_patterns = {}
endif
let g:neocomplcache_force_omni_patterns.ocaml = '[^. *\t]\.\w*\|\h\w*|#'

" OCP-indent
autocmd FileType ocaml execute "set rtp+=" . substitute(system('opam config var share'), '\n$', '', '''') . "/ocp-indent/vim/indent/ocaml.vim"

VS Code中的配置很简单,装上Ocaml and Reason IDE,就好了。这里面还有一个神器Imandra,可以粗浅的看作是Ocaml中LiquidHaskell,而且是商业化的。

Imandra IDE

总结

Aquamacs简洁的配置用来做快速的原型开发很合适。效果如下图所示,代码补全与Utop:

Merlin 与 Emacs 配合

Macvim/Vim更适合需要快速加载的大型项目,加载速度是emacs的痛点。效果如下图所示,Omni代码补全:

Merlin 与 Vim 配合

题外话:时代在不断进步,SpaceVimSpacemacs逐渐趋于成熟,很多主流的编程语言完全可以尝试新的开发环境。各自有各自的特点可以穿插交替使用。Sublime Text感觉已经凉了,VS Code是更好的选择,除了本身背后有微软一个团队在做(Visual Studio的技术积累),开放的社区能提供更多更快的特性支持。但是Sublime Merge横空出世,可以做为Github Desktop的代替品,相对来说Git或者diff这种单一功能的工具也许更适合一个微型团队持续维护与支持。