The following page describes in detail the differences between the OCaml and F# languages. It’s a good read for anyone familiar with OCaml and an even better read for those who are not. For the first line of the summary declares
Functors, OCaml-style objects, labels and option arguments are not supported. Some common functors like Set.Make and Hashtbl.Make are simulated by returning records of functions.
Simulating functors by returning records of functions sounds interesting. Let’s take a closer look at what functors in OCaml are.
OCaml Functors
Chapter 2 of the OCaml manual has a pretty good example of using functors. I have to admit that just finding a good example was somewhat of a chore, which suggests either functors aren’t used a whole lot by OCaml programmers or nobody understands them.
The example starts by declaring a signature to represent types that are orderable.
#type comparison = Less | Equal | Greater;;
type comparison = Less | Equal | Greater
#module type ORDERED_TYPE =
sig
type t
val compare: t -> t -> comparison
end;;
module type ORDERED_TYPE = sig type t val compare : t -> t -> comparison end
We’ll fall back on our object oriented upbringing and use an interface to model the same signature in F#.
type comparison = Less | Equal | Greater
type ORDERED_TYPE<’a> =
abstract t : ‘a
abstract compare : ‘a -> ‘a -> comparison
Now a structure is created for strings. Notice how there is no explicit connection between the structure and the signature.
#module OrderedString =
struct
type t = string
let compare x y = if x = y then Equal else if x < y then Less else Greater
end;;
module OrderedString : sig type t = string val compare : ‘a -> ‘a -> comparison end
We have no choice but to explicitly implement our interface signature.
type OrderedString(t : string) =
interface ORDERED_TYPE<string> with
member me.t = t
member me.compare x y = if x = y then Equal else if x < y then Less else Greater
For those paying attention you’ll see a subtle difference between the two OrderedString declarations. The F# declaration returns an instance of a string for t instead of the type of string. In fact, whereas the F# definition appears to be an instance of type the OCaml version appears to be a type of a type.
Implementing Set as a Functor
The type signature are done, let’s move on to the meat of building our functor. We’ll start with the signature.
module Set :
functor (Elt : ORDERED_TYPE) ->
sig
type element = Elt.t
type set = element list
val empty : ‘a list
val add : Elt.t -> Elt.t list -> Elt.t list
val member : Elt.t -> Elt.t list -> bool
end
And examine the implementation of the signature piece by piece.
#module Set =
functor (Elt: ORDERED_TYPE) ->
struct
type element = Elt.t
type set = element list
So a set is a functor that takes an ordered type as a parameter. The type is then extracted and stored in the element type. I have a feeling our F# definition will have to be quite different.
type Set<’a,’con> when ‘con :> ORDERED_TYPE<’a> () =
And so it is. With F# we can’t combine the constraint and underlying type as a single parameter. Unlike OCaml we have no way of extracting the underlying type from the container type. This results in an unfortunate redundant construction.
So the construction of our types are different, let’s analyze the functions.
let empty = []
let rec add x s =
match s with
[] -> [x]
| hd::tl ->
match Elt.compare x hd with
Equal -> s (* x is already in s *)
| Less -> x :: s (* x is smaller than all elements of s *)
| Greater -> hd :: add x tl
let rec member x s =
match s with
[] -> false
| hd::tl ->
match Elt.compare x hd with
Equal -> true (* x belongs to s *)
| Less -> false (* x is smaller than all elements of s *)
| Greater -> member x tl
And the corresponding F# implementation.
member me.empty : ‘con list = []
member me.add (x : ‘con) (s : ‘con list) =
let rec add (x : ‘con) (s : ‘con list) =
match s with
| [] -> [x]
| hd::tl ->
match x.compare x.t hd.t with
| Equal -> s (* x is already in s *)
| Less -> x :: s (* x is smaller than all elements of s *)
| Greater -> hd :: add x tl
add x s
member me.is_member (x : ‘con) (s : ‘con list) =
let rec is_member (x : ‘con) (s : ‘con list) =
match s with
| [] -> false
| hd::tl ->
match x.compare x.t hd.t with
| Equal -> true (* x belongs to s *)
| Less -> false (* x is smaller than all elements of s *)
| Greater -> is_member x tl
is_member x s
The fundamental difference with the F# code is we’re forced to work with the constraint instead of the underlying type. Because the compare function is only available on instances of ordered types we can only pass those types into our set.
The compare function in the OCaml example however is attached to type itself instead of an instance of the type. Remember how our OCaml structure was more analogous to a type of type rather than an instance of a type? This allows us to solve problems at the type level instead of always relying on runtime dispatch for polymorphism.
Applying the Set Functor
So we’ve built a signature for an ORDERED_TYPE. We’ve created a structure for a string type that implements the signature. We’ve created a functor called Set that can be applied to the structure. So let’s finish this off and do the application.
#module StringSet = Set(OrderedString);;
module StringSet :
sig
type element = OrderedString.t
type set = element list
val empty : ‘a list
val add : OrderedString.t -> OrderedString.t list -> OrderedString.t list
val member : OrderedString.t -> OrderedString.t list -> bool
end
The application of the functor creates a new set for ordered strings. We can now use this set with functions that only work with strings.
#StringSet.member “bar” (StringSet.add “foo” StringSet.empty);;
- : bool = false
The application of our F# “functor” is slightly messier because of the inherent redundancy.
let StringSet = Set<string,OrderedString>()
And of course we have to wrap our strings in OrderedStrings.
let result = StringSet.is_member (OrderedString(“bar”)) (StringSet.add (OrderedString(“foo”)) StringSet.empty)
Does F# Compete Against Java or Other Functional Languages
Some further tricks with interfaces or a record of functions may solve the problem encountered above, but we continue to get the sense that .Net really just isn’t designed with functional languages in mind. Here’s another situation where the F# type system doesn’t appear to be up to snuff with a fellow functional friend. I think most people would agree .Net was created to compete with Java and it shows.
So will this legacy be the stone around F#’s neck that prevents it from ever really being able to compete with Haskell or OCaml? F# may become a great replacement for C# or Java programs, but will the .Net type system ever evolve to the point where F# can solve problems at the type level? With the mutable nature of the .Net API’s and the large legacy code base that must be supported, maybe F# would have been better off staying in the lab and forging the way forward for a proper .Net 2.0.
Full Source Code
#light
type comparison = Less | Equal | Greater
type ORDERED_TYPE<’a> =
abstract t : ‘a
abstract compare : ‘a -> ‘a -> comparison
type OrderedString(t : string) =
interface ORDERED_TYPE<string> with
member me.t = t
member me.compare x y = if x = y then Equal else if x < y then Less else Greater
type Set<’a,’con> when ‘con :> ORDERED_TYPE<’a> () =
member me.empty : ‘con list = []
member me.add (x : ‘con) (s : ‘con list) =
let rec add (x : ‘con) (s : ‘con list) =
match s with
| [] -> [x]
| hd::tl ->
match x.compare x.t hd.t with
| Equal -> s (* x is already in s *)
| Less -> x :: s (* x is smaller than all elements of s *)
| Greater -> hd :: add x tl
add x s
member me.is_member (x : ‘con) (s : ‘con list) =
let rec is_member (x : ‘con) (s : ‘con list) =
match s with
| [] -> false
| hd::tl ->
match x.compare x.t hd.t with
| Equal -> true (* x belongs to s *)
| Less -> false (* x is smaller than all elements of s *)
| Greater -> is_member x tl
is_member x s
//By applying the Set functor to a structure implementing an ordered type, we obtain set operations for this type
let StringSet = Set<string,OrderedString>()
let result = StringSet.is_member (OrderedString(“bar”)) (StringSet.add (OrderedString(“foo”)) StringSet.empty)
printfn “%A” result
System.Console.ReadLine()

Do OCaml and Haskell compete against each other, or mainstream languages? Sure, they’ve got fancy type system features, but they don’t provide convenient access to the extensive .NET or Java class libraries. Besides, neither of them has unit of measure abstractions and OCaml doesn’t have anything like active patterns or computation expressions as far as I’m aware.
On a less flippant note, I think that F# hits a nice pragmatic sweet spot. Certainly, I’d love it if F# were to acquire more cutting-edge type system features such as higher order types, but in my day to day work I don’t find the lack of them crippling. For the most part, F# makes it possible to write concise code that can easily interop with a large amount of code that other people write, and it’s too easy to downplay the significance of that.
Units of measure, active patterns, and computation expression are all “nice to have” features, but compositionality is the core feature of functional programming. Ocaml style functors and Haskell style monads just aren’t possible in F#. Sure, we can simulate composibility, but the above example shows that it’s still too difficult.
I agree that that F# is a great pramgatic language that can be in the place of C# or VB. Hopefully, F# will become the language of choice for .Net developers.
I still question whether the whole .Net stack needs to be rewritten in a modern immutable language. The async pattern is flat out horrible. How many programmers really understand mutex’s, waithandles, and reader writer queues? How many of the of those same .Net api’s are safe or performant in mult-threading enviroments?
Keith — nice writeup, but a bit hard to cut and paste into toplevels as all straight quotes got replaced by slanted ones.
[...] « OCaml Functors as Interfaces [...]
Hmm. I don’t think that you need to rewrite the whole .NET stack to get language level features. Scala is proof of that: a language with variance, implicits, abstraction over type constructors etc in an OO setting, that runs on the JVM _and_ .NET.
.NET is more likely to evolve in the dynamic language direction than in stronger typing in the near future. Which, frankly, I think is a good thing. Java generics are proof that some type system additions contribute more to the problem than to the solution. Can’t hurt to provide some counter balance.
On mutability and parallellism: yes, immutability makes this easier. However, mutability also makes a lot of other things easier. Performance optimizations for example. So I’m not sure we should dismiss it so easily. The examples you give (waithandles etc) are the assembly language of concurrent programming. Some recent initiatives in .NET include software transactional memory, the task parallel library and the concurrency and coordination runtime.
I’m just saying: it’s natural to be frustrated when translating a concept in one language to another that doesn’t have direct support for it. I think it is a mistake to dismiss F# based on the fact that is does not support functors, or (pick your favourite language concept), and to dismiss the whole of .NET(!) with it.
Kurt
Thanks Matthew et al. this is a relevant topic.
RE:
” … I have to admit that just finding a good example was somewhat of a chore, which suggests either functors aren’t used a whole lot by OCaml programmers or nobody understands them. … ” Matthew Doig
” … but compositionality is the core feature of functional programming. Ocaml style functors and Haskell style monads just aren’t possible in F#. Sure, we can simulate composibility, but the above example shows that it’s still too difficult. …” Anonymous
” … I’m just saying: it’s natural to be frustrated when translating a concept in one language to another that doesn’t have direct support for it. … ” Kurt
? Is a good example of functors in OCAML, “Tilings as a programming exercise” by Guy Cousineau, (Theoretical Computer Science 281 (2002) 207 – 217) [also with Mauny "The Functional Approach to Programming"]?
Frustrated translating it to F# led to “The Haskell School of Expression, Learning Functional Programming Through Multimedia”, by Paul Hudak, and your Blog.
Here’s the papers conclusion:
” Now we can summarize the construction of tilings in one functor that takes all the necessary ingredients as parameters:
module Construct_tiling
(Group: CANONICAL_GROUP)
(Geom: GEOMETRY)
(GenMap: MAPPING with type source = Group.element
and type dest = Geom.transformation)
(GenColorMap: MAPPING with type source = Group.element
and type dest = Permutation.permutation)
(Tile: TILE with type transformation =
Geom.transformation * Permutation.permutation)
=
Make_tiling
(Make_generator_from_canonical
(Make_canonical_generator(Group))
(MakePair (Make_morphism (Group) (GenMap) (Geom.Tgroup))
(Make_color_morphism (Group) (GenColormap)))
(Tile)
This leads to a simpli)ed graphical representation which appears in Fig. 3.
7. Conclusion
What we have obtained is a very generic program that can produce any tiling with a
computable symmetry group that operate transitively on the tiles. …”