Hacker News new | ask | show | jobs
by rwmj 3778 days ago
Good article. I'm involved with a large-ish OCaml project[1] and some of these things apply there too.

In particular we avoid "academic" features of the language like functors[2] and first class modules, because they obscure the flow of the code and are a headache for ordinary programmers to understand. I often get requests from people from the OCaml academic community asking if we have any available positions, and the answer has so far always been no.

[1] https://github.com/libguestfs/libguestfs/tree/master/v2v

[2] https://realworldocaml.org/v1/en/html/functors.html

6 comments

>In particular we avoid "academic" features of the language like functors[2] and first class modules, because they obscure the flow of the code and are a headache for ordinary programmers to understand.

If you're hiring OCaml programmers who can't understand (or learn to understand) functors, you're probably doing something wrong. Even using the stdlib Hashtbl requires an understanding of functors.

As I said, the problem with functors is the same as the problem with OO - it obscures the flow of the code. You can look at some function call, and not understand (just by looking at the text) which code executes next. I'd prefer not to hire people who will "functorize" (nor OO-ize) everything. When I said "ordinary programmers", I'm referring mainly to myself, but also to casual contributors.
Hmm, I found functors a bit confusing on my first encounter with the language, but I wouldn't call them 'academic'. If you've ever used Haskell typeclasses, they serve almost the same purpose.

In OO land, they're just a way to ensure that an argument satisfies an interface, exposing certain public functions and properties — just like an object in Java has to implement the Comparable interface in order to be sorted in a collection.

Functors are modules that depend on another module. This works like a function whose argument is a module with type given by a signature.

There isn't anything exactly analogous in Java. Functor application can introduce new type definitions at compile time and enforce static type safety. You need this so that you can statically require that you can only take unions of sorted collections whose types came from the same ordering module applied to the same ordered set module.

Yes, I know my example isn't perfect, but I've found is a good way of explaining the general concept to people not familiar with ML's module system. Thanks for your explanation though!
Haskell typeclasses are a headache that many Haskell experts eschew.
Wow, really? I learned some Haskell on the side a few years ago, and typeclasses were one of my favorite features. They allowed so much expressiveness from such small building blocks. They seemed like a cornerstone of the language.

I'm surprised to hear they're often eschewed.

Highly abstract and general typeclasses for standard mathematical and algebraic concepts are extremely useful and not eschewed. With them you can do genuinely generic programming in a syntactically convenient way. Examples include: Functor, Applicative, Monad, Num, Floating, Integral, MonadState, MonadReader, Profunctor, Contravariant, ...

Typeclasses which are ad hoc, specific, and typically defined on a per project basis, are much more debatable. If you have the concept of "rendering to the screen" and you have typeclass Renderable with a render method then this is really no better than just writing separate functions for each instance of the Renderable. This isn't genuinely generic programming, it's just symbol overloading.

Hey, you're talking about my library Renderable - and I'm totally up to finding a more idiomatic way to express the problem. It just so happened that type classes were the easiest way to do that.
Ha, sorry, didn't mean to make it sound like I was talking about anything in particular! I just made up that example on the spot. A "Renderable" thing fits into a common pattern where you see typeclasses used in this way.

(Are you talking about this library? https://hackage.haskell.org/package/renderable-0.1.0.0/docs/...

I don't actually see a Renderable class there anyway.)

I wouldn't say they are eschewed.

Haskell programmers do seem to prefer typeclasses that come equipped with some set of meaningful "laws" that help to reject "unreasonable" instances.

And even without that, they are very useful for data type conversions and the like.

Are you saying that you never hire anyone at all to work on your project, or that you think so little of the community that created the language your project uses that you lie to them about job openings?
Neither of those.
> I often get requests from people from the OCaml academic community asking if we have any available positions, and the answer has so far always been no.

I don't understand what you're saying. Are those applicants to Red Hat, or developers asking to contribute to libguestfs that you say no to.

I mean hires. Of course anyone is welcomed who sends patches.
I understand why one would avoid first class modules (I don't use them a lot either). However I fail to see why functors are too complicated, since they are basically just functions. Could you explain ?

Also, according to this[1], There are basically three main contributors, including you, so I fail to see how training would be an issue ...

[1]: https://github.com/libguestfs/libguestfs/graphs/contributors

That graph covers the whole project, not virt-v2v. Is there a way to limit it to particular directories? Not that I could see very easily.
Monads are essentially functors...
The word "functor" means in OCaml something very different to what it means in Haskel.
Not just essentially. All monads are functors.
Not in OCaml. It's a different concept.
There seem to be a hundred language definitions of Functor. Even Haskell's doesn't exactly correspond to the mathematical understanding of the term (if it did, Set would be a functor)

C++ is the worst offender, though.

How is Set a functor in a mathmatical sense?
You can define a function setMap such that if you setMap any function f from a -> b where Set a and Set b are valid types, then setMap f lifts f to a function Set a -> Set b. setMap will also satisfy the functor laws (or law, if you understand the parametricity derivation of the second law, which I don't :) ). Or in other words, setMap id = id.

In fact, the mapping is absolutely obvious. Haskell slightly brain damages us by assuming that setMap would have to apply to all a->b functions, which can't be done because a and b need to be Ord.

Although apparently it _can_ be done in GHC 8. ish.

https://gist.github.com/ekmett/f783ea6af2e041b7b887

... A monoid in the category of endofunctors