

You have to be explicit about which module you’re using at all times, even though 99% of the time only one could apply. When the type class resolution is unique, but complicated, there’s no mental overhead for the Haskell programmer but getting all the right modules is a lot of overhead for the OCaml programmer. It also lets us write functions that are polymorphic under a class constraint. In OCaml you have to explicitly take a module argument to do this. If you want to start composing such functions, it gets tedious extremely fast.
And then even once you’re using a module, you can’t overload a function name. See: +
vs +.
. Basically modules and type classes solve different problems. You can do some things with modules that you cannot ergonomically do with type classes, for example. create a bit-set representation of sets of integers, and a balanced search tree for sets of other types, and expose that interface uniformly from the same module functor. But Haskell has other ways to achieve that same functionality and more.
OCaml’s type system cannot replicate the things you can do with Haskell’s higher kinded types, type families, or data kinds at all (except for a fraction of Haskell’s GADTs).
I use vim, or spacemacs with evil mode (emacs distribution with sensible shortcuts and vim emulation). Or VSCode with spacemacs emulation.
You will pass your current productivity in less than a month. All of the things you describe are easily done in VSCode with vim emulation (I prefer the full spacemacs emulation but it’s not actually a huge difference). You won’t have to move your hands away from the normal typing spot on your keyboard – no home and end, just 0 and $. No control+arrow keys, just w and b (or e or even more motion options). Highlighting is as easy as v and then motion commands. And there are so many more useful things that vim (and vim emulation) make simple and fast. Orthogonal VSCode features like multi cursors still work.