So, I recently had the time to spend a few hours discussing languages with someone who hasn’t used Haskell or OCaml or the like, but likes functional programming and strict type-systems.
In particular, I’d have liked to make a better showing in explaining why we value our higher-kinded tooling, functors - having used them in anger and at work, I’m a fan; and I feel like I’ve seen good arguments for the power of the ‘module-language functors’ approach over things like typeclasses … but I’m actually at more of a loss here than I’d expected.
I started out with a classic “fully generic map
” example …
module type Mappable = sig
type 'a t
val our_map : ('a -> 'b) -> 'a t -> 'b t
end
module ListMappable : Mappable with type 'a t = 'a list = struct
type 'a t = 'a list
let our_map = List.map
end
module OptionMappable : Mappable with type 'a t = 'a option = struct
type 'a t = 'a option
let our_map f = function
| None -> None
| Some x -> Some (f x)
end
module MakeMap (M : Mappable) = struct
let our_map f x = M.our_map f x
end
let list_result = MakeMap(ListMappable).our_map (fun x -> x + 1) [1; 2; 3] in
let option_result = MakeMap(OptionMappable).our_map (fun x -> x + 1) (Some 1) in ...
… but I was surprised at how much cleaner Kotlin’s (chatGPT-generated, forgive me, I don’t know Kotlin yet) example was than what I’d build w/ OCaml:
fun <T, R, C : Collection<T>> C.map(transform: (T) -> R): List<R> {
val result = mutableListOf<R>()
for (item in this) {
result.add(transform(item))
}
return result
}
Now, of course, this result isn’t fully generic in the collection-return-type; and attempting to extract that blew the complexity up hugely … okay, fine, point to OCaml there. But nonetheless, generally speaking, I didn’t feel that example did a good job of demonstrating what functors are good for in practice, that more mainstream-style ‘generics’ and ‘interfaces’ and the like don’t provide.
I feel like the times they’ve really benefitted me in practice (already relatively rare, because half the time, I’m just using functors to work around a different shortcoming of OCaml, instead of using them for something they’re really ideal for, ugh) were in larger projects; so I could definitely lean on the code-reuse / separation-of-concern benefits of functorial design, but I’d really like to show that they do also help express certain algorithmic/modularity concepts … I just, off my head, can’t think of a good specific example from all my time using OCaml.
tl;dr What’re y’all’s favourite educational examples that show the expressivity benefits of typing-features like functors (and relatedly, typeclasses)?