# Report on first steps in OCaml

**URL:** <https://discuss.ocaml.org/t/report-on-first-steps-in-ocaml/13022>\
**Category:** Learning\
**Created:** [September 14, 2023, 7:29pm UTC](https://discuss.ocaml.org/t/report-on-first-steps-in-ocaml/13022 "2023-09-14T19:29:58Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![asymmetric](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/asymmetric/32/4633_2.png) [@asymmetric](https://discuss.ocaml.org/u/asymmetric)\
**Post date:** [September 14, 2023, 7:29pm UTC](https://discuss.ocaml.org/t/report-on-first-steps-in-ocaml/13022/1 "2023-09-14T19:29:58Z")

</div>

This is a report of the first steps on my journey to learning OCaml.

To give you some context, I am a relatively experienced programmer with very little free time, so I was looking for a crash-course, i.e. the quickest possible introduction to the language, so that I can get to work and learn as I implement my side-project.

I know there’s [work being done](https://github.com/ocaml/ocaml.org/pull/1514) on the documentation site, and that’s fantastic. This report dates back to a month ago, so it might be that some resources have been updated in the meantime. cc @professor.rose who asked me about my experience as a newcomer 🙂

Anyway, here goes:

- The first question is: which resource do I use? The choice seems to be between [Learn OCaml](http://ocaml.org/learn) and RWO. I ended up choosing the former
- Digression: I’m a Nix user, so had to first figure out how to take procedural install instructions (e.g. `opam switch`) and turn them into declarative environment declarations for a Nix shell
- Setting up LSP: First I needed to figure out the difference between OCaml-LSP and Merlin (turns out, the former uses the latter);
  - the [official docs](https://ocaml.org/docs/up-and-running#first-steps-with-ocaml) say that Vim users don’t need to setup up LSP, and use Merlin directly – why?

- how do I test for equality? No mention of the semantics of `=` that I could easily find
  - even “worse”, no mention of the highly unusual `<>` 🙂

- I ended up finding this info [here](https://ocamlbook.org/conditional-expressions/), but knowing what to search for, the [Cornell course](https://courses.cs.cornell.edu/cs3110/2021sp/textbook/basics/operators.html) also has this info
- the [stdlib pages](https://v2.ocaml.org/api/List.html#1_Associationlists) don’t list individual functions in the sidebar, which makes it hard to skim them for what I’m looking for
- additionally, they don’t provide any examples, which makes it much harder to figure out how to use the functions
- `;` vs `;;` vs `in`: here I got confused. The [examples](https://ocaml.org/docs/first-hour#expressions-and-variables) only deal with the top-level, and introduce the `;;` syntax which AFAIU is only used there. I got tripped up by the difference between `;` and `in`.

For example, running `ocamlc` against this is a syntax error:

```ocaml
type nucleotide = A | C | G | T

let hamming_distance s t =
  (* iterate over s and t, whihc have the same length, using an index i.
      compare the character s[i] and t[i]. if they're different, increase the number
  *)
  let distance = ref 0 in
  let func i c =
    if s.[i] <> t.[i] then
      (* distance := !distance + 1 in *)
      incr distance;

  String.iteri func s;

  distance

```

(it needs to be `String.iteri func s in`)

But this works:

```ocaml
type nucleotide = A | C | G | T

let hamming_distance (s: nucleotide list) (t: nucleotide list) =
  (* iterate over s and t, whihc have the same length, using an index i.
      compare the character s[i] and t[i]. if they're different, increase the number
  *)
  let distance = ref 0 in
  List.iter2 (fun x y -> if x <> y then incr distance) s t;

  distance

```

There is obviously a good reason for this, but it would be great to have a place I can easily find which explains this. I couldn’t find one.

- compiler errors: compiling the failing snippet above only returns:

```bash
$ ocamlc hamming.ml
File "hamming.ml", line 16, characters 0-0:
Error: Syntax error

```

It would be nice to have the compiler spit out the line where the syntax error happened, and maybe even tell me what I should do instead (in this case, `;` should become `in`)

---

<div class="post-metadata">

**Author:** ![alan](https://avatars.discourse-cdn.com/v4/letter/a/a87d85/32.png) [@alan](https://discuss.ocaml.org/u/alan)\
**Post date:** [September 14, 2023, 11:00pm UTC](https://discuss.ocaml.org/t/report-on-first-steps-in-ocaml/13022/2 "2023-09-14T23:00:25Z")

</div>

> [@asymmetric](#):
>
> (it needs to be `String.iteri func s in`)

Be careful. The `in` is supposed to go before the `String.iteri func s` to end the definition of `func`. Because you put the `in` after, you’re calling `String.iteri func s` in the definition of `func`. This would in turn be another compile error because recursive functions need to be explicit with `let rec`.

This is probably what you want:

```auto
type nucleotide = A | C | G | T

let hamming_distance s t =
  (* iterate over s and t, whihc have the same length, using an index i.
      compare the character s[i] and t[i]. if they're different, increase the number
  *)
  let distance = ref 0 in
  let func i c =
    if s.[i] <> t.[i] then
      (* distance := !distance + 1 in *)
      incr distance
  in
  String.iteri func s;
  distance

```

Also, I think some OCaml programmers would prefer using an accumulator parameter for `distance` instead of a mutable reference.

---

<div class="post-metadata">

**Author:** ![Joel](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/joel/32/4466_2.png) [@Joel](https://discuss.ocaml.org/u/Joel)\
**Post date:** [September 15, 2023, 1:19am UTC](https://discuss.ocaml.org/t/report-on-first-steps-in-ocaml/13022/3 "2023-09-15T01:19:05Z")

</div>

This post gives a good explanation of OCaml semicolons: [https://baturin.org/docs/ocaml-faq/](https://baturin.org/docs/ocaml-faq/)

The main thing to understand is that while OCaml does have syntax that allows you to use it imperatively, it can be a little janky and counterintuitive, especially at the edges where it meets the declarative syntax.

Semicolons are a good example of this. In OCaml, code that would look like this in an imperative language:

```js
function helper_function(a,b) {
    // do something...
    return c;
};

print("Starting!");
var a = /* something... */;
var b = /* something else... */;
function_that_changes_program_state(a);
var c = helper_function(a,b);
print(c);

```

would instead look something like this:

```ocaml
let helper_function a b = (* do something *) in
let _ = print_endline "Starting!" in
let a = (* something... *) in
let b = (* something else... *) in
let _ = function_that_changes_program_state a in
let c = helper_function a b in
print_function_for_whatever_the_type_of_c_is c

```

Even when we don’t care about the value something produces (like when we’re printing or changing program state) we still structure stuff like `let (* X *) = (* Y *) in (* Z *)`, we just use `_` on the left hand side to show that we’re not binding the value of `(* Y *)` to anything.

The semicolon is just syntactic sugar for this: instead of writing `let _ = (* Y *) in (* Z*)`, we can write `(* Y *); (* Z *)`. We can use it to rewrite the example as:

```ocaml
let helper_function a b = (* do something *) in
print_endline "Starting!";
let a = (* something... *) in
let b = (* something else... *) in
function_that_changes_program_state a;
let c = helper_function a b in
print_function_for_whatever_the_type_of_c_is c

```

But that’s all it is; for example, writing a semicolon at the end of the last line of the above code is not correct and may cause a syntax error depending on where in the program that block occurs.

Your first code example desugars to something like:

```ocaml
type nucleotide = A | C | G | T

let hamming_distance s t =
  (* iterate over s and t, whihc have the same length, using an index i.
      compare the character s[i] and t[i]. if they're different, increase the number
  *)
  let distance = ref 0 in
  let func i c =
    if s.[i] <> t.[i] then
      (* distance := !distance + 1 in *)
      let _ = incr distance in
      let _ = String.iteri func s in
      distance

```

You could rewrite it to avoid the awkwardness of the imperative parts of OCaml like so:

```ocaml
type nucleotide = A | C | G | T

let rec hamming_distance s t =
  (* Remove the first element of s and the first element of t.
     Calculate the Hamming distance between the rest of s and the rest of t,
     then add one to it if the first element of s and the first element of t
     are different. If s and t are both empty, their Hamming distance is zero.
     If only one is empty they started as different lengths, and so throw an
     error.
  *) 
  match s, t with
  | s_head::s_tail, t_head::t_tail -> (* lists are not empty *) 
      (if s_head <> t_head then 1 else 0) + (hamming_distance s_tail t_tail)
  | [], [] -> (* lists are both empty *)
      0
  | _ -> invalid_arg "Lists are not the same length" 
           

```

Or, you even go for

```ocaml

type nucleotide = A | C | G | T

let rec hamming_distance s t = 
  List.fold_left2
    (fun dist a b -> if a <> b then dist + 1 else dist) 0 s t

```

---

<div class="post-metadata">

**Author:** ![otini](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/otini/32/3533_2.png) [@otini](https://discuss.ocaml.org/u/otini)\
**Post date:** [September 15, 2023, 4:10pm UTC](https://discuss.ocaml.org/t/report-on-first-steps-in-ocaml/13022/4 "2023-09-15T16:10:56Z")

</div>

> [@asymmetric](#):
>
> Digression: I’m a Nix user, so had to first figure out how to take procedural install instructions (e.g. `opam switch`) and turn them into declarative environment declarations for a Nix shell

Regarding this, installing opam from NIxpkgs and then doing things imperatively works fine, and that’s what I usually do, because I move between switches a lot and find it cumbersome to write Nix files all the time. However, I agree that an easy-to-find resource detailing how to depend on OCaml declaratively would be nice. I know [this one](https://ryan.freumh.org/blog/ocaml-nix/).

Edit: disclaimer: this one is probably not for beginners though.

---

<div class="post-metadata">

**Author:** ![meitros](https://avatars.discourse-cdn.com/v4/letter/m/b5a626/32.png) [@meitros](https://discuss.ocaml.org/u/meitros)\
**Post date:** [September 16, 2023, 12:42am UTC](https://discuss.ocaml.org/t/report-on-first-steps-in-ocaml/13022/5 "2023-09-16T00:42:58Z")

</div>

You skipped mentioning something (I believe), which is that you also went to [https://exercism.org/](https://exercism.org/) to try learning ocaml by solving problems. Like an interactive version of [Exercises](https://ocaml.org/problems).

I think this because I tried that site and encountered (and got stuck at) an identical nucleotide problem. For me, because I was using Base/Core I didn’t understand how to do variant equality or why it was so hard to look up how to do it (answer, use a ppx that generates equality functions on that data type)

FWIW I think a better version of exercism would be really fun for people to learn ocaml. When I was interview studying to apply for jobs I solved a bunch of problems at [https://www.algoexpert.io/](https://www.algoexpert.io/) - kind of a much more polished version of leetcode - and enjoyed studying more than I thought I would. The problems should probably be more tailored for ocaml than typical algorithm questions, but it’s fun to learn a language by solving smaller coding problems.

---

<div class="post-metadata">

**Author:** ![mudrz](https://avatars.discourse-cdn.com/v4/letter/m/8e7dd6/32.png) [@mudrz](https://discuss.ocaml.org/u/mudrz)\
**Post date:** [September 20, 2023, 12:48pm UTC](https://discuss.ocaml.org/t/report-on-first-steps-in-ocaml/13022/6 "2023-09-20T12:48:50Z")

</div>

I would also modify the OCaml example with:

```diff
let helper_function a b = (* do something *) in
- let _ = print_endline "Starting!" in
+ let () = print_endline "Starting!" in
let a = (* something... *) in
let b = (* something else... *) in
- let _ = function_that_changes_program_state a in
+ let _ : string = function_that_changes_program_state a in
let c = helper_function a b in
print_function_for_whatever_the_type_of_c_is c

```

to avoid ignoring a value incorrectly or not even calling a function due to partial application

---

<div class="post-metadata">

**Author:** ![asymmetric](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/asymmetric/32/4633_2.png) [@asymmetric](https://discuss.ocaml.org/u/asymmetric)\
**Post date:** [September 27, 2023, 8:12am UTC](https://discuss.ocaml.org/t/report-on-first-steps-in-ocaml/13022/7 "2023-09-27T08:12:40Z")

</div>

The stdlib is practically invisible to search engines, it seems. I tried searching for `ocaml failwith` in Google, DDG and Kagi, and none of them returned the function defined [here](https://v2.ocaml.org/api/Stdlib.html#1_Exceptions).

What’s the best place to report this? I’m not sure where the repo for the API website is.

---

<div class="post-metadata">

**Author:** ![Khady](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/khady/32/469_2.png) [@Khady](https://discuss.ocaml.org/u/Khady)\
**Post date:** [September 28, 2023, 6:15am UTC](https://discuss.ocaml.org/t/report-on-first-steps-in-ocaml/13022/8 "2023-09-28T06:15:55Z")

</div>

> [@asymmetric](#):
>
> What’s the best place to report this? I’m not sure where the repo for the API website is.

I believe it would be [GitHub - ocaml/ocaml.org: The official OCaml website.](https://github.com/ocaml/ocaml.org)
