One thing I don't like about OCaml is that I always find myself writing the same things, like "to_string" functions for my variant types (although there must be some ways to alleviate this burden). Also, when your programs use abstract data types you lose the benefits of pattern matching. In that case, I'm happier with languages like Go or Ada with a friendlier syntax.
For instance, here we have Option
module Option = struct
let scott (some : 'a -> 'r)
(none : 'r)
(opt : 'a option) =
match opt with
| Some a -> some a
| None -> none
end
For Option, since it's non-recursive, the Scott Encoding and the recursor/inductor/Church Encoding are identical. Here's a linked list, though module LL : sig
type 'a t
val fold : ('a -> 'r -> 'r) -> 'r -> ('a t -> 'r)
val scott : ('a -> 'a t -> 'r) -> 'r -> ('a t -> 'r)
end = struct
type 'a t = Cons of 'a * 'a t | Nil
let rec fold cons nil = function
| Cons (h, t) -> cons h (fold cons nil t)
| Nil -> nil
let scott cons nil = function
| Cons (h, t) -> cons h t
| Nil -> nil
end
Anyway, the pattern should be more clear now. These provide effectively "functionalized" pattern matching which you can apply whenever you need. In particular, you can think of these as expressing a (potentially partial) "view" of the abstract type. For instance, my linked list might have not been a linked list exactly but instead some kind of tree, but `scott` and `fold` let me expose a "view" of that tree as though it were a linked list.