Anyone using OCaml for 2024 Advent of Code (AOC)?

Anyone using OCaml for 2024 AOC?

I have not done any coding for months – so using this opportunity to brush up on my novice OCaml skills.

5 Likes

I had tried… my version differs… GitHub - F-Loyer/AoC2024

I guess
List.find_all (fun x -> x = v) lst |> List.length
is more clever than my
List.fold_left (fun acc m -> if n=m then acc+n else acc) 0.

I’ve been doing it for a few years now, trying to catch up to past editions whenever I have the time (meaning, never). It’s a neat sandbox to play with some syntax tricks (abusing .%{} and the like until this does not feel like OCaml anymore :slight_smile: ) and it’s great inspiration for coding exercises for students.

A word of advice though, during AOC season, it is best to put a warning or spoiler tags in discussions about particular problems. The AOC author also asks to not publish the full text of puzzles or one’s particular input (so I add mine to a private repo, which is a submodule of my main one).

Now, back to meaningful work until the next treat.

My Reason solutions are here: ezrast / advent2024 · GitLab

I’m also participating this year: GitHub - vshender/advent-of-code: My solutions to the Advent of Code problems.

how can i rewrite my day 3 to make it more readable? it just looks really really bad :frowning:

Your part1 is already pretty readable, for that kind of code. I think you can only improve it by using a regex engine or a tool like ocamllex or sedlex.
For part 2, maybe you could simplify a bit by dropping the text that is between don't() and do() (reconstructing a new string) and apply part1 on that. Maybe insert a phony # so that mul(1,2don't()do()) won’t be considered valid.

My two cents.

1 Like

An easy thing to do would be to swap the order of the tuple you are matching on such that the previous character appears before the current one.

A more involved one would be to allow your solve functions to consume more than one character per iteration. If you see a m you already know what you want the next characters to be. So you can try to consume them eagerly before calling solve again. This decreases the number of cases in your match statements and allows you to drop the num1 and num2 arguments.

1 Like

A small PSA that it is requested not to publish one’s inputs (see author’s comment on Twitter, for some value of X)

(I’m seeing how long I manage to work in OCaml, as opposed to on OCaml, this year at dra27/AOC2024, although my solutions tend to be coded to amuse me, which occasionally includes adopting style which would never fly on a PR :wink:)

See also @sabine’s List on Bluesky

I’ve doing it in OCaml again this year as well (I’ve tried Rust last year, and OCaml in 2022), pretty straightforward for now: GitHub - dlesbre/advent-of-code: Puzzle solutions for advent of code 2022 and 2023

1 Like

About swapping rest.[0] and prev, I tried this when I was solving the puzzle

For case 'm', prev can anything for the match to be valid. Swapping rest.[0] and prev means I’ll have to move _ in front of 'm', but the type checker seems very unhappy about this

As mentioned above: I like doing AOC to get a chance to write OCaml for myself (i.e my solutions involve a bunch of let (>>>) f g x = f x |> g and a series of >>> (i.e forward function compositions) that I don’t think is at all maintainable lol).

Since we are sharing, I’ve this guilty pleasure of mine:

  val ( .%{} ) : ('a, 'b) Hashtbl.t -> 'a -> 'b
  (** [h.%{k}] is [Hashtbl.find h k]. *)

  val ( .%?{} ) : ('a, 'b) Hashtbl.t -> 'a -> 'b option
  (** [h.%?{k}] is [Hashtbl.find_opt h k]. *)

  val ( .%{}<-) : ('a, 'b) Hashtbl.t -> 'a -> 'b -> unit
  (** [h.%{k}<- v] is [Hashtbl.replace h k v]. *)

  val ( %? ) : ('a, 'b) Hashtbl.t -> 'a -> bool
  (** [h %? k] is [Hashtbl.mem h k]. *)

  val ( %- ) : ('a, 'b) Hashtbl.t -> 'a -> unit
  (** [h %- k] is [Hashtbl.remove h k]. *)

  val ( ~% ) : ('a* 'b) list -> ('a, 'b) Hashtbl.t
  (** [ ~% l] creates a fresh Hashtbl.t from the bindings listed in [l]. *)

  val ( or ) : 'a option -> 'a -> 'a
  (** [ a or b ] is [v] if [a] is [Some v] and [b] if [a] is [None]. *)

and then stuff like that:

let table = ~%[ "FR", 0; "IT", 0; "VN",0 ]
let f key =
   if table %? "FR" then Printf.printf "Bonjour\n";
   table.%{key} <- 1 + (table.?%{key} or 0);
   table %- "FR" (* au revoir *)

of course with generic Hashtbl.t using generic equality and hash. :partying_face:

5 Likes

Huh, I did not at all know about using {} in infix operators; wild!

Taken straight from the manual (ok, the language extension part, but still, this one has been there since 4.06).

1 Like

I find that to be very readable. Why is it ‘guilty’, i.e. what would considered questionable style about this?

To give some context, OCaml code that I write for my day job is either:

  • Exercises, examples, exams … for Bachelor level students
  • Academic prototypes of type systems and such where I collaborate with a few people (other researchers, PhD students, interns,…)

In both case, I aim at writing idiomatic OCaml code. Since using these indexing operators is not a well established convention, I don’t want to introduce any difficulties for people reading the code.
Plus there are some dangers. For instance, although writing ( e1 or e2 ) is cute in recreational code, I only do it because I know that in my case, e2 will always be a constant (a default value). If people where to abuse it with arbitrary expressions that would be bad (evaluation order, side effects, …).

Rather, I would say that I use personal projects such as the AoC to experiment with more experimental part of the language.

1 Like

But operators are quite nice… my day4 proposition use heavily .$() as a shorthand of String.get. Most language have a short expression for such a thing (even Ada which is quite verbose). Why shouldn’t OCaml have it ?

Sure, it is not common to have very multiple such operators, but in many language, Strings, Arrays, Associative maps have them. (With languages that support overloading, .[]could be use with many many things).

1 Like

The standard .[] operator (in "Abc".[0] ) is a built-in short-hand for String.get

1 Like