几百年前就想入门OCaml了,但是一直咕咕,现在终于下定决心学习一下。
Haskell人眼中的OCaml生态
首先是OCaml的特点:
- 快,与Haskell相比编译飞快,性能也强
 - 不lazy,不怕莫名其妙泄露啦
 - 默认impure,随便使用IO,可变状态,函数式C
 - 基于module系统的抽象
 - 类型体操能力不如hs
 - 比起Haskell混乱的工具链生态,OCaml更统一稳定
 
语言实现:Haskell vs. OCaml
Parser 了解了一下Haskell和OCaml的parser生态很不一样。Haskell有很多parser combinator库,而且是开箱即用的,例如megaparsec,错误处理很漂亮,不需要怎么定制化就可以实现一个漂亮的toy;
反观OCaml,
angstrom是最接近Haskell的parser combinator库,也有do notation,但总体还是没Hs的好用,错误信息也不如megaparsec。menhir是parser generator,很快很强大。
LLVM 都有LLVM绑定,可惜我不会
eDSL Haskell完爆了
pretty-printer Haskell用组合子风格的pretty-printer库,而OCaml使用Format库,并不是组合子风格的。
总的来说,和Haskell相比,OCaml根本算不上FP,纯度太低了!不过我完全同意它作为一个更好用的工程语言,不论哪方面都比Haskell适合做一个干净的项目。
关于Opam
其实Haskell生态是挺乱的,相比之下opam+dune的组合就统一、稳定许多。
Switch
Opam相当于 OCaml 的包管理器 + 版本管理器 + 项目环境隔离工具。Opam的环境隔离单位是switch,我们这样可以创建一个switch:
1  | opam switch create 5.2.0  | 
switch里面会维护一个围绕着一个OCaml编译器版本的环境,例如上面的命令,就创建了一个OCaml5.2.0的环境。这包括了这个版本的编译器、这个环境下的各个用到的库的编译产物。
全局 vs. 本地
上面的命令创建的switch环境是全局的。也就是说,在使用的时候(例如我们要编译不同的项目),需要手动切换不同的switch来使用对应的编译器(和库的)版本。例如如果现在需要一个5.0.0的编译器,我们可以:
1  | opam switch 5.0.0  | 
opam/dune是通过你运行它的shell的环境变量来确定使用哪个switch的,因此要正常运行,还需要执行:
1  | eval $(opam env)  | 
来设置这些变量。当然,我们可以把它写在shell的配置文件里,这样每次打开shell都能自动配好这些变量。
opam还可以在项目目录建立本地的switch,例如我们切换到项目目录,执行:
1  | opam switch create . 5.2.0  | 
会在这个目录下创建一个_opam目录,而不是在全局。使用
1  | opam switch  | 
可以查看所有的switch。可以发现全局switch的名字是对应的编译器版本名,而本地switch则是一个路径,指向那个本地的目录。在那个目录下(的所有目录),opam都会自动使用那个本地的switch。如此以来就不会和别的项目影响。
另外,opam下载的库的源文件都是全局管理的,相同的库不会反复下载,可以放心使用。
- 本文作者: Frankenstein
 - 本文链接: https://salty-frankenstein.github.io/blog/2025/09/24/【杂记】OCaml,启动!/
 - 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!