f# - 你能向我解释一下 OCaml 仿函数吗?

标签 f# ocaml functor

这个问题在这里已经有了答案:




9年前关闭。




Possible Duplicate:
In Functional Programming, what is a functor?



我对OCaml不太了解,我研究F#有一段时间了,很了解。

他们说 F# 缺少 OCaml 中存在的仿函数模型。我试图弄清楚仿函数到底是什么,但维基百科和教程对我帮助不大。

你能帮我解开这个谜吗?提前致谢 :)

编辑:

我已经捕获了重点,感谢所有帮助过我的人。您可以将问题作为与以下内容完全相同的副本关闭:In Functional Programming, what is a functor?

最佳答案

如果您来自 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 的对象怎么办?哪个没有实现那个特定的接口(interface)?如果您想动态定义排序功能怎么办?一种方法是按如下方式传入比较器:
    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# 不支持仿函数,因此您必须求助于一些困惑的解决方法。对于上面的场景,我几乎总是将“仿函数”存储在我的数据结构中,并带有一些辅助帮助函数,以确保它被正确复制:
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))

关于f# - 你能向我解释一下 OCaml 仿函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2370240/

相关文章:

F#:不能在签名中隐藏类型缩写?为什么不?

interface - 使用接口(interface)派生函数 - F#

function - OCaml:没有定义值的柯里化(Currying)

functional-programming - 了解多提示分隔的延续的 API

collections - list.map 和 list.collect 的区别

f# - 如何最好地捕获失踪的let!、do!、return和return!在 F# 的计算表达式中

OCamlbuild 和 camlp4.macro

haskell - 任何与 fmap 具有相同多态类型的函数都必须等于 fmap?

c++ - 如何“适应”仿函数以与 map /多重 map 一起使用?