HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Is this use of (let ... and ...) in OCaml poor style?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
thispoorocamlstyleletanduse

Problem

In other languages, I prefer to arrange source files so that simpler and more widely useful concepts are introduced before implementation details, and I try where possible to make complex implementation details top-level functions so that I can separate them out and let the main function read like a high-level algorithm description.

OCaml obviously has an interface/source distinction, but even with a sparse well-documented interface like

type t
(** Blah blah blah *)

val important_operator : t -> t -> t
(** Blah blah blah *)


I've been tempted to do things like

let rec important_operator a b =
  let a', b' = foo a b in
  let a', b' = iterate_until_convergence (=)
                 (fun (a, b) -> bar (baz a b))
                 (a', b') in
  merge a', b'

(* Implementation details *)

and foo a b = ...

and bar x = ...

and baz a b = ...

and merge a b = ...


Is this poor style? Does it affect the ability of IDE-users to navigate source files?

Solution

It's not idiomatic OCaml indeed.

  • "and" is an effective way to say "watch out for mutual recursion".



  • OCaml encourages you to use nested functions instead! As The Structure of OCaml programs says: "Nested functions are, however, very useful and very heavily used in OCaml."



You would write this code as follows:

let important_operator a b =
  let foo a b = ... in
  let bar x = ... in
  let baz a b = ... in
  let merge a b = ... in
  let a', b' = foo a b in
  let a', b' = iterate_until_convergence (=)
                 (fun (a, b) -> bar (baz a b))
                 (a', b') in
  merge a', b'


Of course, you don't need to only use nested functions, you can also define bar or baz before defining important_operator. OCaml tends to only use functions that were defined "earlier", so using and for this is abusing the system.

Code Snippets

let important_operator a b =
  let foo a b = ... in
  let bar x = ... in
  let baz a b = ... in
  let merge a b = ... in
  let a', b' = foo a b in
  let a', b' = iterate_until_convergence (=)
                 (fun (a, b) -> bar (baz a b))
                 (a', b') in
  merge a', b'

Context

StackExchange Code Review Q#15558, answer score: 5

Revisions (0)

No revisions yet.