Is there any OCaml’s best practices? What materials can help me to improve my OCaml code?
A little biased, but these might be of use:
There are many good practices that are general to functional languages, not specific to OCaml.
For example, having the key data structure as the last argument is very useful when chaining calls. [see yminsky’s reply] Using abstract types when possible is also a good idea. This point is documented in the Elm design guidelines but it is equally applicable to OCaml.
Of course, some communities (or even members in the same community) may not agree on a point - e.g. having custom infix operators (how many are too many?).
This one’s not especially widely agreed upon. The Base/Core guidelines specify putting the primary element as the first argument, though the use of labeled arguments provides some flexibility on argument order.
Is there a place I can read Base/Core design guidelines?
This chapter describes some of the major components:
in the section “Designing with Modules”, and in particular in the “Create Uniform Interfaces” part.
We do have a more detailed internal style guide, but that’s not currently public.
I have a limited style guide OCaml Towards Clarity and Grace that includes references to others style guides. I am happy to include additions and critical discussions.
A style guide can help to become aware of some OCaml issues but there is a whole range of knowledge that could improve your code that is not covered by the topic of style: knowing more about clever functional algorithms or advanced usage of the type system. The books mentioned by others are a good start.
Good point, I stand corrected then. Although I’m curious why the Base/Core guidelines make the suggestion that they do. There doesn’t seem to be any reasoning provided there (or am I just not looking carefully enough?). It would be useful if, beneath each point in the guideline, the rationale behind it were written down. That way a project can “opt in” to guidelines after determining what points are applicable to their code base.
Did you report this issue?
Although I’m curious why the Base/Core guidelines make the suggestion that they do. There doesn’t seem to be any reasoning provided there (or am I just not looking carefully enough?).
Having the main type be first argument, with heavy use of named parameters, lets us write calls in the same way as having it be the last argument. If we have a bunch of operations on some
type t, we can chain them together in two ways. Assuming that the API is written with the
t parameter being last, we can write:
let t' = op1 t |> op2 arg |> op3 arg1 arg2
Now, in the Base/Core style,
op3 would take
t as the first parameter, and the rest would be named. So we could write:
let t' = op1 t |> op2 ~param1:arg1 |> op3 ~param1:arg1 ~param2:arg2
If we didn’t use either style, we’d need to use some intermediate bindings to store and pass along the results of the different
ops, or use a function like
flip to effectively move around the order of arguments (which would not work in all cases).
Hope that helps.