您能给我解释一下 OCaml 函子吗? [复制]

2024-06-18

可能的重复:
在函数式编程中,什么是函子? https://stackoverflow.com/questions/2030863/in-functional-programming-what-is-a-functor

我对 OCaml 不太了解,我学过 F# 一段时间并且很了解它。

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

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

EDIT:

我明白了重点,感谢所有帮助过我的人。您可以将问题关闭为与以下内容完全相同的副本:在函数式编程中,什么是函子? https://stackoverflow.com/questions/2030863/in-functional-programming-what-is-a-functor/2031421#2031421


如果您来自 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使用< and >运营商?

在幕后,它做了这样的事情:

> 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)

It works,但是如果您正在编写一个用于插入、查找、删除等树操作的模块,则需要客户端在每次调用任何内容时传递一个排序函数。

如果 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))
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

您能给我解释一下 OCaml 函子吗? [复制] 的相关文章

随机推荐

  • cspade() R 错误

    我正在尝试从电缆调制解调器的事件中挖掘规则 链接的是数千个文件 当我尝试在所有设备的合并文件 1200 万行 上运行 cspade 算法时 它会花费数小时来消耗 RAM 直到它用完我可用的所有 64 GB 因此 我尝试仅在一台设备的链接文件
  • 实体框架:无需映射即可调用存储过程

    有没有一种方法可以在不使用实体框架函数映射的情况下使用存储过程 这很好 但是当向存储过程添加任何更改时 这完全是垃圾 我知道您可以刷新存储过程映射 但事实并非如此高效的 大多数时候 当您更新映射时 它不会检测到更改 这是非常烦人的 到目前为
  • 字符串替换多个值

    我有一个看起来像这样的字符串 布拉布拉 亚达亚达 布拉布拉 亚达亚达 有没有办法只替换前两个 或最后两个 以便我可以获得下一个输出 Bla bla a href link1 yada yada a bla bla yada yada 如有必
  • 使 QLabel 的像素图透明

    我有一个带有 QLabel 和像素图的主窗口 我想让它透明 或不那么不透明 我正在使用下面的代码 ui gt label gt setAttribute Qt WA TranslucentBackground ui gt label gt
  • 无需开发者模式安装开发的应用程序

    我开发了一个 Windows 10 UWP 应用程序 这个应用程序应该在公司使用 所以我通过Visual Studio 2015的内置工具构建它 为此 我遵循了本指南 打包适用于 Windows 10 的通用 Windows 应用 http
  • C++ 通过引用传递动态分配的二维数组

    这个问题是基于之前提出的问题而提出的 通过已知大小的引用多维数组传递 https stackoverflow com questions 529109 c pass by reference multidimensional array w
  • 级联通用接口

    我正在构建自己的框架来包装通过暴露的接口Microsoft Office Interop 我将 Office 范围的功能包装到第一组接口中 然后由第二组功能继承 这些功能依赖于应用程序 这是一个简化版本 Region Office Wrap
  • 将更新的图像保存到 PhotoKit 时缺少图像元数据

    我在更新图像的元数据并将其保存回照片库时遇到问题 一切works除了更改后的图像元数据丢失了之前存在的条目 并且我在操作图像或执行照片库更改块时没有收到任何错误 另外 在写回图像之前的字典看起来就像原始字典加上我在调试器中的字典 我的问题是
  • dplyr / left_join 中的嵌套管链

    在尝试获取分组滞后变量的过程中 仅使用这是不可能的 lag 建议的解决方案是将数据拉出 滞后不同的行 然后重新加入它 我更喜欢在不创建中间对象的情况下执行此操作 并且希望在链中间执行此操作 然而 它似乎没有像我预期的那样工作 问题似乎是使用
  • 如果其中一个 ant 测试失败,如何使 Jenkins 显示失败

    我有几个测试应该执行 无论彼此是否成功 我希望 Jenkins Hudson 显示red如果这些测试中至少有一项失败 则灯亮 我当前的 为了清楚起见而简化 配置如下 ci sh ant 构建 xml
  • Python 2.7从非默认目录打开多个文件(对于opencv)

    我在 64 位 win7 上使用 python 2 7 并拥有 opencv 2 4 x 当我写 cv2 imread pic 时 它会在我的默认 python 路径中打开 pic 即C Users Myname 但是我如何设法浏览不同的目
  • Flutter无法从url加载图像

    图片资源服务捕获异常 解析图像编解码器时抛出以下 ImageCodecException 加载网络图像失败 图片网址 https cdn sportmonks com images soccer leagues 5 png https cd
  • 如何在 MAMP 上显示错误?

    我有 MAMP 但我不知道如何在其上显示错误 当我的 php 代码出现错误时 它只显示空白页 我在 Google 上搜索过 我发现我必须在所有文件夹和版本上将其更改为 display errors on 并将其包含在我的页面上 错误报告 E
  • 将 SQL Server 与 Dart 结合使用

    我还没有找到很好的答案 所以我想尝试一下得到答案 将 Microsoft SQL Server 与 Dart 结合使用的最佳方式是什么 我需要它能够从基本上任何操作系统 网络和移动设备上使用它 我觉得最好的方法可能是 GraphQL 但我对
  • 一对一的DataMapper关联

    我对 DataMapper 非常陌生 我正在尝试为以下场景创建模型 我有许多用户 有用户名 密码等 他们也可以是玩家或裁判员或两者兼而有之 因此单表继承不是一个选项 基本模型是 class User include DataMapper R
  • 长变量名在 dplyr 中失败

    长度超过 39 个字符的字符串在 dplyr 中失败 返回错误 错误 索引超出范围 我错过了什么还是这是一个错误 40 个字符不起作用 library dplyr names iris 5 lt vvv 5vvv10vvv15vvv20vv
  • SwipeListView 47 度:以编程方式滑动第一项

    我想滑动第一个项目滑动列表视图 https github com 47deg android swipelistview on Activity启动以向用户显示SwipeListView是可滑动的 如何使用此 UI 元素以编程方式执行此操作
  • “neo4j-admin”不被识别为内部或外部命令、可操作程序或批处理文件

    我正在尝试将 neo4j 2 2 数据导入 neo4j 3 1 文档 https neo4j com docs operations manual current upgrade deployment upgrading 告诉我跑 neo4
  • 普罗米修斯:我如何用两个不同的指标求和

    我有两个不同的指标 具有字段类型的 metric a metric b 具有字段类型 相同 我试图总结同一类型的 a 和 b 如果类型仅存在于 metric a 上而不存在于 metric b 上 它应该返回 metric b 的结果 我在
  • 您能给我解释一下 OCaml 函子吗? [复制]

    这个问题在这里已经有答案了 可能的重复 在函数式编程中 什么是函子 https stackoverflow com questions 2030863 in functional programming what is a functor