在OCaml中编写以下代码的惯用方法是什么,具有更好的可读性?
let big_function arg =
let big_helper_fn acc = function
| p -> ...
...
...
... foo(arg)
...
...
| _ -> ...
in
let small_helper_1 a b =
...
...
in
let small_helper_2 a b =
...
...
in
fold big_function default_acc
%> small_helper_1 aa1
%> small_helper_2 aa2
由于两个原因,将内部功能提升到外面可能是不受欢迎的:
foo(arg)
)。如果有更多参数,这将变得很麻烦,例如big_function
接受3个参数,big_helper_fn
使用所有参数,累加器也是3个元素的元组。big_function
具有相同的缩进深度。如果OCaml有第一类where
条款,这不会有问题。我确实为此找到了PPX和另一个Github repo。
请按照答案中建议的方法提供大型项目的书籍/风格指南/官方文档/名称的参考。
编辑:我在这个代码示例中遇到的麻烦是可读性受损,因为big_function
的实际定义与顶部的原始let big_function ...
语句相隔很多。因此,我正在寻找一种更具可读性的惯用语。
答案 0 :(得分:1)
您的代码看起来已经非常OCamlish。许多大型项目都是以这样的方式编写的:请参阅OCaml编译器实现本身。我喜欢Haskell中的where
,但我个人反对非纯语言中的任意where
因为它可能使副作用的排序非常混乱,这可能导致很难修复的错误。将where
的定义仅限于非扩展表达式是可以的,但我不确定您提到的PPX是否执行此类检查。
我从来没有这样做过,但是你可以把'#34; main"首先使用let rec
:
let big_function arg =
let rec go () =
fold big_helper_fn default_acc
%> small_helper_1 aa1
%> small_helper_2 aa2
and big_helper_fn acc = function
..
and small_helper_1 a b =
..
and small_helper_2 a b =
..
in
go ()
或者,您可以使用本地模块:
module BigFunctionHelpers(A : sig val arg : t end) = struct
open A
let big_helper_fn acc = function ... foo(arg) ...
let small_helper_1 a b = ...
let small_helper_2 a b = ...
end
let big_function arg =
let module H = BigFunctionHelpers(struct let arg = arg end) in
let open H in
fold big_helper_fn default_acc
%> small_helper_1 aa1
%> small_helper_2 aa2
有时我从父函数中提取包含许多参数的本地定义时会这样做。
答案 1 :(得分:1)
在不知道辅助函数中发生了什么的情况下很难说,但一般来说,您可以将它们作为顶级函数提取出来。这有几个好处:
还有一些缺点,如你所说: