Nếu bạn đến từ một vũ trụ OOP, sau đó nó có thể giúp suy nghĩ của một mô-đun tương tự như một lớp tĩnh. Tương tự như các lớp tĩnh .NET, mô-đun OCaml có các hàm tạo; không giống như .NET, các mô-đun OCaml có thể chấp nhận các tham số trong các hàm tạo của chúng. Một hàm functor là một tên đáng sợ cho đối tượng mà bạn truyền vào trong hàm tạo module.
Vì vậy, sử dụng ví dụ kinh điển của một cây nhị phân, chúng tôi thường viết nó trong F # như thế này:
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 và dandy. Nhưng F # biết cách so sánh hai đối tượng thuộc loại 'a
bằng cách sử dụng các toán tử <
và >
?
Đằng sau hậu trường, một cái gì đó làm nó như thế này:
> let gt x y = x > y;;
val gt : 'a -> 'a -> bool when 'a : comparison
Alright, cũng những gì nếu bạn có một đối tượng kiểu Person
mà không thực hiện mà giao diện cụ thể không? Điều gì sẽ xảy ra nếu bạn muốn xác định chức năng phân loại khi đang di chuyển?Một cách tiếp cận chỉ là để vượt qua trong Comparer như sau:
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)
Nó làm việc, nhưng nếu bạn đang viết một module cho các hoạt động cây với chèn, tra cứu, di chuyển, vv, bạn yêu cầu khách hàng để vượt qua trong một chức năng đặt hàng mỗi khi họ gọi bất cứ thứ gì.
Nếu functors F # được hỗ trợ, cú pháp giả của nó có thể trông như thế này:
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)
Vẫn trong cú pháp giả, bạn muốn tạo module của bạn như vậy:
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
Thật không may, F # doesn 't hỗ trợ functors, vì vậy bạn phải rơi trở lại trên một số cách giải quyết lộn xộn. Đối với kịch bản trên, tôi hầu như luôn luôn lưu trữ "functor" trong cấu trúc dữ liệu của tôi với một số hàm trợ giúp bổ trợ để đảm bảo nó được sao chép chính xác:
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))
Tôi không phải là F # hay OCaml guru. 't làm điều này như là một câu trả lời chính thức, nhưng tôi nghĩ rằng http://blog.matthewdoig.com/?p=152 có thể giúp bạn ra một chút trong việc giải thích các functors và làm thế nào F # được xung quanh sự vắng mặt của họ. –
Tôi đã đọc bài viết đó trước, cũng có blog.matthewdoig.com/?p=155. Tôi đang ở nửa chừng để hiểu điều đó :) – Bubba88