Si viene de un universo OOP, entonces probablemente ayude a pensar en un módulo como análogo a una clase estática. Similar a las clases estáticas .NET, el módulo OCaml tiene constructores; a diferencia de .NET, los módulos OCaml pueden aceptar parámetros en sus constructores. Un functor es un nombre que suena aterrador para el objeto que pasa al constructor del módulo.
Así, utilizando el ejemplo canónico de un árbol binario, nos escribimos normalmente en C# como esto:
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)
fino y elegante. Pero, ¿cómo sabe F # cómo comparar dos objetos del tipo 'a
con los operadores <
y >
?
Detrás de las escenas, el hacer algo como esto:
> let gt x y = x > y;;
val gt : 'a -> 'a -> bool when 'a : comparison
Muy bien, así que si usted tiene un objeto de tipo Person
la que no implementa la interfaz en particular? ¿Qué pasaría si quisieras definir la función de clasificación sobre la marcha?Un enfoque es sólo para pasar en el comparador de la siguiente manera:
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)
Se funciona, pero si usted está escribiendo un módulo para las operaciones de árboles con parte, las operaciones de búsqueda, extracción, etc., que requieren que los clientes pasan en una función de pedido cada vez que llaman a algo.
Si F # apoyado funtores, su sintaxis hipotética podría tener este aspecto:
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)
Todavía en la sintaxis hipotética, necesitará crear su módulo como tal:
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
Desafortunadamente, F # doesn No admite funtores, por lo que debe recurrir a algunas soluciones desordenadas. Para el escenario anterior, casi siempre almacenaría el "funtor" en mi estructura de datos con algunas funciones auxiliares auxiliares para asegurarse de que se copia todo correctamente:
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))
No soy un F # ni gurú OCaml por lo gané Esto lo hago como una respuesta formal, pero estoy pensando que http://blog.matthewdoig.com/?p=152 puede ayudarlo un poco a explicar los funtores y cómo F # soluciona su ausencia. –
He leído ese artículo primero, también está blog.matthewdoig.com/?p=155. Estoy a medio camino para entender eso :) – Bubba88