views:

564

answers:

4

Hi!

I don't know much about OCaml, I've studied F# for some time and quite understand it.

They say that F# misses functor model, which is present in OCaml. I've tried to figure out what exactly functor is, but wikipedia and tutorials didn't help me much.

Could you please illuminate that mystery for me? Thanks in advance :)

EDIT:

I've caught the point, thx to everyone who helped me. You can close the question as exact duplicate of: http://stackoverflow.com/questions/2030863/in-functional-programming-what-is-a-functor/2031421#2031421

+6  A: 

Functors are modules parameterized by modules, i.e. a reflection from modules to modules (ordinary function is reflection from values to values, polymorphic function is reflection from types to ordinary functions).

See also http://ocaml-tutorial.org/modules#Functors

ygrek
I was 10 seconds late :-)I am not a specialist, and I understood this explanation.
yogsototh
This is a good explanation of what OCaml functors *are*, and what they *are good for* is programming generic data structures (see the implementation of Set in the OCaml standard library, it's perhaps the simplest example of functor) and generally offering an efficient, statically type-checked alternative solution to many problems that you could also solve with object-oriented programming.
Pascal Cuoq
Wish I were that lucky).. So, if I understand it right way: functors are the way to make new modules by parametrizing existing modules such as `Set`?
Bubba88
Just like generics are for classes, functors are for modules. Is that right way to think?
Bubba88
In order to represent a set as a binary tree, you need an ordering function. The type of elements and their ordering function compose a module Elt. The functor Set builds a type and access functions for sets from module Elt.
Pascal Cuoq
To the best of my understanding, "generics" in OO-languages are more comparable to parametric polymorphism that you already have in F# and OCaml (example: 'a list). Parametric polymorphism is not sufficient when an abstract type is not enough (example: to build sets as binary trees, you need an ordering function over elements).
Pascal Cuoq
+1  A: 

I understood, the reply on other thread was much helpful : http://stackoverflow.com/questions/2030863/in-functional-programming-what-is-a-functor/2031421#2031421

Bubba88
Prof. Norman Ramsey always gives good answers to such questions!
Yin Zhu
Professor Norman Ramsey has nice avatar too))
Bubba88
+1  A: 

Check out this data structures in ocaml course:

http://www.cs.cornell.edu/Courses/cs3110/2009fa/lecturenotes.asp

the functor lecture: http://www.cs.cornell.edu/Courses/cs3110/2009fa/lectures/lec10.html

and the splay tree implementation using functor: http://www.cs.cornell.edu/Courses/cs3110/2009fa/recitations/rec-splay.html

Yin Zhu
+7  A: 

If you come from an OOP universe, then it probably helps to think of a module as analogous to a static class. Similar to .NET static classes, OCaml module have constructors; unlike .NET, OCaml modules can accept parameters in their constructors. A functor is a scary sounding name for the object you pass into the module constructor.

So using the canonical example of a binary tree, we'd normally write it in F# like this:

type 'a tree =
    | Nil
    | Node of 'a tree * 'a * 'a tree

module Tree =
    let rec insert v = function
        | Nil -> Node(Nil, v, Nil)
        | Node(l, x, r) ->
            if v < x then Node(insert v l, x, r)
            elif v > x then Node(l, x, insert v r)
            else Node(l, x, r)

Fine and dandy. But how does F# know how to compare two objects of type 'a using the < and > operators?

Behind the scenes, its doing something like this:

> let gt x y = x > y;;

val gt : 'a -> 'a -> bool when 'a : comparison

Alright, well what if you have an object of type Person which doesn't implement that particular interface? What if you wanted to define the sorting function on the fly? One approach is just to pass in the comparer as follows:

    let rec insert comparer v = function
        | Nil -> Node(Nil, v, Nil)
        | Node(l, x, r) ->
            if comparer v x = 1 then Node(insert v l, x, r)
            elif comparer v x = -1 then Node(l, x, insert v r)
            else Node(l, x, r)

It works, but if you're writing a module for tree operations with insert, lookup, removal, etc, you require clients to pass in an ordering function everytime they call anything.

If F# supported functors, its hypothetical syntax might look like this:

type 'a Comparer =
    abstract Gt : 'a -> 'a -> bool
    abstract Lt : 'a -> 'a -> bool
    abstract Eq : 'a -> 'a -> bool

module Tree (comparer : 'a Comparer) =
    let rec insert v = function
        | Nil -> Node(Nil, v, Nil)
        | Node(l, x, r) ->
            if comparer.Lt v x then Node(insert v l, x, r)
            elif comparer.Gt v x then Node(l, x, insert v r)
            else Node(l, x, r)

Still in the hypothetical syntax, you'd create your module as such:

module PersonTree = Tree (new Comparer<Person>
    {
        member this.Lt x y = x.LastName < y.LastName
        member this.Gt x y = x.LastName > y.LastName
        member this.Eq x y = x.LastName = y.LastName
    })

let people = PersonTree.insert 1 Nil

Unfortunately, F# doesn't support functors, so you have to fall back on some messy workarounds. For the scenario above, I would almost always store the "functor" in my data structure with some auxillary helper functions to make sure it gets copied around correctly:

type 'a Tree =
    | Nil of 'a -> 'a -> int
    | Node of 'a -> 'a -> int * 'a tree * 'a * 'a tree

module Tree =
    let comparer = function
        | Nil(f) -> f
        | Node(f, _, _, _) -> f

    let empty f = Nil(f)

    let make (l, x, r) =
        let f = comparer l
        Node(f, l, x, r)

    let rec insert v = function
        | Nil(_) -> make(Nil, v, Nil)
        | Node(f, l, x, r) ->
            if f v x = -1 then make(insert v l, x, r)
            elif f v x = 1 then make(l, x, insert v r)
            else make(l, x, r)

let people = Tree.empty (function x y -> x.LastName.CompareTo(y.LastName))
Juliet
Thank you for this helpful example. You've managed to do it without a line of Ocaml code, huh))
Bubba88
How is this different than accepting an instance of IEqualityComparer, for example, in the constructor? It could be implemented ad-hoc using object expressions.
Daniel
@Daniel: that's basically the point. OCaml functor is basically the same thing as passing some sort of object into a module's constructor. But since F# modules == .NET static classes, and .NET static constructors don't accept parameters in their constructors, you need to jump through hoops to get the same sort of functionality.
Juliet