OCaml Programming: Correct and Efficient and Beautiful

(cs3110.github.io)

119 points | by smartmic 13 hours ago ago

36 comments

  • crvdgc 12 hours ago ago

    Apart from being tied with Jane Street's libraries, Real World OCaml is "deeper" in that it also talks about implementation details. This book has a more "introduction to functional programming via OCaml" vibe. Both are good textbooks with different emphases.

    The main author Michael Clarkson also started a similar lecture series on Software Foundations using Rocq (Coq)[1]. Not sure if that's still updated though.

    [1]: https://github.com/clarksmr/sf-lectures

  • teiferer 12 hours ago ago

    Could an OCaml expert give a quick take on the view that if FP, why not go all the way and do Haskell instead? I mean, if "correct, efficient, beautiful" are attributes of OCaml (and I know opinions differ, but let's assume for a moment..) then shouldn't they be attributes of Haskell too, maybe even more so in some ways?

    • mbac32768 10 hours ago ago

      FP is great but not necessarily at all costs.

      OCaml is immediate by default instead of lazy, and allows imperative code with side-effects. Both escape hatches from the pure FP world.

      So, performance is easier to reason about and you can interact with your side-effecty real world stuff without having to reorganize your whole program around the correct monad.

      Most of the time you want your loops to be higher order functions but once in awhile you want to just build a vector from a for loop. OCaml let's you do it without it being a whole intervention.

      • nextos 9 hours ago ago

        Also, a major differentiator is that Haskell deals with effects primarily by using monads, whereas many modern functional languages (e.g. Koka or Flix) are being designed from the ground up to use algebraic effects instead. OCaml is also embracing effects. Haskell has some effect libraries as well, but monadic code is everywhere. IMHO, as someone who loves Haskell, algebraic effects will make FP much more approachable.

      • djtango an hour ago ago

        It's really worth noting that one of the biggest real world Haskell codebases in the world (ie Standard Chartered) wrote their own compiler to make Haskell evaluation strict and make it easier to do interop with C++

        Laziness by default was definitely an opinionated design choice for a language when using it in production

      • droideqa 10 hours ago ago

        What about Haskell STM versus OCaml Multicore Eio?

    • Syzygies 11 hours ago ago

      I started with SML in the 1980's, implementing a core math algorithm (Grobner bases) used in my K&R C computer algebra system Macaulay. Then I got this idea there should be a related algorithm in a different problem domain (Hilbert bases) and I managed to convert my code in twenty minutes. It ran. This completely blew my mind, on par with switching from punched card Fortran to an APL terminal in the 1970's.

      Everyone talks a good line about more powerful, expressive programming languages till they need to put in the work. Ten years effort to program like ten people the rest of your life? I'm 69 now, I can see how such an investment pays off.

      I moved to OCaml. Studying their library source code is the best intro ever to functional programming, but I felt your "all the way" pull and switched to Haskell. (Monads make explicit what a C program is doing anyway. Explicit means the compiler can better help. What it comes down to is making programming feel like thinking about algebra. This is only an advantage if one is receptive to the experience.)

      I'm about to commit to Lean 4 as "going all the way". Early in AI pair programming, I tested a dozen languages including these with a challenging parallel test project, and concluded that AI couldn't handle Lean 4. It keeps trying to write proofs, despite Lean's excellence as a general purpose programming language, better than Haskell. That would be like asking for help with Ruby, and AI assuming you want to write a web server.

      I now pay $200 a month for Anthropic Max access to Claude Code Opus 4 (regularly hitting limits) having committed to Swift (C meets Ruby, again not just for macOS apps, same category error) so I could have first class access to macOS graphics for my 3-manifold topology research. Alas, you can only build so high a building with stone, I need the abstraction leverage of best-in-category functional languages.

      It turns out that Opus 4 can program in Lean 4, which I find more beautiful than any of the dozens of languages I've tried over a lifetime. Even Scheme with parentheses removal done right, and with far more powerful abstractions.

      • pmarreck 9 hours ago ago

        Have you looked at Idris 2?

        I'm 53, impressed that you're still going at it at 69!

        • Syzygies 7 hours ago ago

          Yes. I'm impressed with Idris 2. I love how it uses Chez Scheme, my favorite scheme implementation. I contributed for a bit to getting Idris installation working on Apple Silicon Macs based on Racket's port of Chez Scheme, only to learn that I was working with Idris instructions that hadn't been updated.

          Lean 4 is a better supported effort, with traction among mathematicians because of the math formalization goal.

          I have more reasons to want to learn Lean 4. Peel away their syntax, and Lean 4 proofs are the word problem for typed trees with recursion. I find the reliance of AI on artificial neurons as arbitrary as so many advanced life forms on Earth sharing the same paltry code base for eyes, a nose, a mouth, and GI tracts. Just as many physicists see life as inevitable, in a billion runs of our simulation I'm sure AI would arise based on many foundations. Our AI fakes recursion effectively using many layers, but staring at the elementary particles that make up Lean proofs one sees a reification of thought itself, with recursion a native feature. I have to believe this would make a stronger foundation for AI.

          I don't get that same rush looking at Idris. Using Lean 4 for general purpose programming? It must be good training.

          • pmarreck 6 hours ago ago

            I'll have to have a look at Lean 4 then.

            The simulation hypothesis has a flaw IMHO- If it is modelable and therefore computable, it may be subject to the halting problem

    • yodsanklai 11 hours ago ago

      Pros and cons as usual. I worked with both languages professionally but I personally find OCaml more practical, better at programming in the large and easier to write maintainable code. It's a simpler language overall (side effects, strict evaluation). I find the language finds sweet spot between these attributes whereas Haskell is more abstract.

      That being said, Haskell is pretty nice as well but I'd pick OCaml for real world stuff.

      One thing that bothered me with both these languages is that people not fluent with FP could write code that isn't idiomatic at all. It's probably a bit harder to do in Haskell.

    • OneDeuxTriSeiGo 12 hours ago ago

      At least theoretically they could be however OCaml is in large part driven by Jane Street and has been for some time now and Jane Street's entire business model is built around optimizing for ultra high throughput, ultra low latency software where mistakes could cost on the order of hundreds of billions of dollars.

      So my guess would be less that Haskell is not these things (nor couldn't it be) but rather that OCaml has had the external forces necessary to optimise for these things above all else.

    • faldor20 12 hours ago ago

      As someone who has lightly used Haskell and quite heavily used ocaml:

      - Pragmatism: The ocaml community has a stronger focus on practical real projects. This is shown by the kind of packages available on the ecosystem and the way those packages are presented. (A number of Haskell packages I've tried to use often seen to be primarily intellectual pursuit with little documentation on actually using them).

      - Simplicity: Haskell does have some amazing features, but it has so many different ways to do things, so many compiler flags, code can look vastly different from one codebase to another. It's kind of the c++ of FP. Ocaml is definitely more cohesive in its approach.

      Tooling: last I used Haskell the whole ecosystem was pretty rough, with two package managers and a lot of complexity in just setting up a project. Ocaml is not at the level of rust or other modern languages, but is definitely a stop above I'd say.

    • shawn_w 12 hours ago ago

      Personally, I don't like how Haskell considers things like I/O as side effects that have be wrapped in monads. Ocaml feels much more practical.

      Plus, though both languages allow defining new infix operators, ocaml coders are much more restrained about it than haskellers, and I hate having to figure out what >>>>$=<<< does when it shows up in code.

      • Quekid5 10 hours ago ago

        *. sends its regards

        :)

    • KevinMS 9 hours ago ago

      My take is that OCaml lets you sneak a little mutation in, with a little effort, which can make a huge difference in the performance of some algorithms.

      • aguluman 3 hours ago ago

        Yeah. I agree, I have shaved of a few seconds on my algorithm computation through mutation. I felt like I cheated though.

    • skybrian 12 hours ago ago

      I'm not an OCaml or Haskell expert, but I expect that laziness makes performance harder to reason about?

      Edit: but in this case, apparently the book was written for a course at Cornell where they teach both functional and imperative programming using the same language.

      • derriz 12 hours ago ago

        In my experience, reasoning about (or maybe being able to manage) memory consumption is more of an issue for fully lazy languages.

        Having worked on a code-base written in a lazy (Haskel-like) FPL where the architecture relied heavily on laziness, the least pleasant issue to deal with was sudden and obscure explosions in memory consumption.

        Which would of course have a big impact on performance so maybe this was your point also.

      • hermanhermitage 12 hours ago ago

        That’s been my experience. Across the spectrum of languages I’ve found certain features such as dynamic memory, managed memory, memory safety, evaluation model, etc all have an impact on the transparency of understanding time and space characteristics. I spend most of my time in assembly and C, but love the sheer ranges of language options we have today. I put Haskell in the “Miranda” branch of languages which I love for tackling some problems but day to day but I’ve never got a handle on how that translates into predictable characteristics of the generated code.

  • anon-3988 8 hours ago ago

    I just want OCAML to have curly braces, please. And the variable scope thing in OCAML is extremely off putting.

    • zdragnar 7 hours ago ago

      Have you tried reason? Seems like a step in the direction you're looking for anyway

    • debugnik 7 hours ago ago

      You can use the ReasonML syntax with the standard OCaml toolchain, it's the same language with curly braces. (Not to be confused with ReScript which spun off of it, but is now a different language that only targets the JavaScript stack.)

      Do you simply dislike the OCaml syntax or is it some particular quirk?

      > the variable scope thing

      The what thing? Variables are just lexically scoped, are you referring to shadowing?

  • pizlonator 8 hours ago ago

    I would take the FP zealots more seriously if they stopped asserting that FP makes things more correct.

    Zero evidence that this is the case.

    I can tell you that debugging a compiler written in ML is a dumpster fire compared to debugging a compiler written in C++. If take C++ over any FP language for compilers any day of the week.

    • yawaramin 7 hours ago ago

      OCaml is not just FP. It's FP + strong static typing + modular programming + exhaustive pattern matching + fast compiles + great set of built-in compiler lints (eg unused code warnings, mutation warnings). All of these things together help write very reliable code.

    • pjmlp 5 hours ago ago

      Yet all mainstream languages, including C++, keep adding FP concepts.

      Better spend some time having fun with std::variant, visit, and ranges transformers.

    • differentmod 3 hours ago ago

      > I would take the FP zealots more seriously if they stopped asserting that FP makes things more correct.

      Depends on the correctness requirements in question. But overall you are 100% correct about this.

      FP, among other aspects, enables and promotes some ways of reasoning, for instance when mutation is avoided, that can be relatively easy to use to verify correctness of certain types of properties. For instance, induction proofs and some other kinds of mathematical proofs. However, for some other types of correctness properties, imperative programming can be easier to reason about than FP. One possible example is in regards to implementation of algorithms, where for instance an implementation of quicksort in C is likely to be more concise and clearer than a "true" quicksort implementation in Haskell. Another possible example is (if one assumes that FP requires garbage collection) that of hard real-time systems, for instance some types of medical devices, where even though some types of garbage collection may be viable, approaches like forgoing dynamic memory allocation (no malloc, no reference counting, no types of garbage collection, etc.) may be easier to reason about regarding achieving the correctness requirement of hard real-time.

      Overall, I definitely agree that ML and FP are not the best for achieving correctness in all cases.

      I personally like to pick and choose between FP and other approaches, and mix them in different ways dependent on the project or task at hand. Like, a purely functional interface with internal mutation in the implementation for optimization. Or, some mutable API that uses FP for some aspects of the implementation where FP is easier to reason about.

      > I can tell you that debugging a compiler written in ML is a dumpster fire compared to debugging a compiler written in C++. If take C++ over any FP language for compilers any day of the week.

      For larger compilers for some requirements, I could for some projects imagine that this is true. But, for smaller compilers with relatively few requirements, the pattern matching and tagged union features of modern ML languages are very popular, and I like having access to those features when writing smaller compilers. If you do not mind spending the time to expound on this topic, I would very much like to know more. Or, maybe some links, like blog posts, that discuss this topic. I am genuinely curious. A blog post could also be shared elsewhere, instead of just lost in some Hacker News discussion. (Maybe I should start blogging myself).

      Also, Hacker News/Ycombinator is censorship-infested.

  • iLoveOncall 12 hours ago ago

    There's absolutely nothing efficient nor beautiful about programming in OCaml.

    • yawaramin 11 hours ago ago

      Username checks out.