我对OCaml了解不多,我已经研究了F#一段时间并且非常了解它。
他们说F#错过了函数模型,它存在于OCaml中。我试图弄清楚究竟是什么算子,但维基百科和教程对我没什么帮助。
你可以为我阐明这个谜吗?在此先感谢:)编辑:
对于帮助过我的每个人,我都明白了这一点。您可以将问题完全复制为:In Functional Programming, what is a functor?
答案 0 :(得分:31)
如果你来自OOP世界,那么将模块视为类似于静态类可能会有所帮助。与.NET静态类相似,OCaml模块具有构造函数;与.NET不同,OCaml模块可以在其构造函数中接受参数。仿函数是传递给模块构造函数的对象的可怕名称。
所以使用二叉树的规范示例,我们通常用F#写这个:
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)
很好,很花哨。但是F#如何知道如何使用'a
和<
运算符比较>
类型的两个对象?
在幕后,它做了这样的事情:
> let gt x y = x > y;;
val gt : 'a -> 'a -> bool when 'a : comparison
好吧,如果你有一个类型Person
的对象没有实现那个特定的接口呢?如果您想动态定义排序功能怎么办?一种方法就是按比例传递比较器:
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)
工作,但如果您正在使用插入,查找,删除等编写树操作模块,则每次调用任何内容时都需要客户端传递一个排序函数。
如果F#支持仿函数,其假设语法可能如下所示:
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)
仍然在假设的语法中,你可以创建你的模块:
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
不幸的是,F#不支持仿函数,所以你必须依赖一些凌乱的解决方法。对于上面的场景,我几乎总是将“functor”存储在我的数据结构中,并带有一些辅助辅助函数,以确保它被正确复制:
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))
答案 1 :(得分:12)
Functors是由模块参数化的模块,即从模块到模块的反射(普通函数是从值到值的反射,多态函数是从类型到普通函数的反射)。
Examples in the manual也很有帮助。
答案 2 :(得分:2)