首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >你能给我解释一下OCaml函数器吗?

你能给我解释一下OCaml函数器吗?
EN

Stack Overflow用户
提问于 2010-03-03 18:07:44
回答 3查看 9.2K关注 0票数 18

可能重复:

In Functional Programming, what is a functor?

我对OCaml了解不多,我研究F#已经有一段时间了,对它也很了解。

他们说F#遗漏了OCaml中存在的函数器模型。我试着弄清楚functor到底是什么,但维基百科和教程对我帮助不大。

你能为我解开这个谜团吗?提前感谢:)

编辑:

我明白了,感谢所有帮助过我的人。您可以将问题作为In Functional Programming, what is a functor?的精确副本来结束

EN

回答 3

Stack Overflow用户

发布于 2010-03-04 02:52:43

如果您来自OOP领域,那么将模块视为类似于静态类可能会有所帮助。与.NET静态类类似,OCaml模块具有构造函数;与.NET不同,OCaml模块可以接受构造函数中的参数。functor是传递到模块构造函数中的对象的一个听起来很可怕的名称。

因此,使用二叉树的规范示例,我们通常会用F#编写它,如下所示:

代码语言:javascript
复制
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类型的对象呢?

在幕后,它是这样做的:

代码语言:javascript
复制
> let gt x y = x > y;;

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

好吧,如果你有一个Person类型的对象,它并没有实现这个特定的接口,那该怎么办呢?如果您想动态定义排序函数,该怎么办?一种方法是只传入比较器,如下所示:

代码语言:javascript
复制
    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#支持函数器,则其假设语法可能如下所示:

代码语言:javascript
复制
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)

在假设的语法中,你可以这样创建你的模块:

代码语言:javascript
复制
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“与一些辅助辅助函数一起存储在我的数据结构中,以确保它被正确复制:

代码语言:javascript
复制
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))
票数 33
EN

Stack Overflow用户

发布于 2010-03-03 18:18:01

函数是由模块参数化的模块,即从模块到模块的反射(普通函数是从值到值的反射,多态函数是从类型到普通函数的反射)。

另请参见ocaml-tutorial on modules

Examples in the manual也很有帮助。

票数 12
EN

Stack Overflow用户

发布于 2010-03-04 00:33:23

页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2370240

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档