问题标签 [first-class-modules]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
915 浏览

types - 使用第一类模块时,类型构造函数“...”将逃脱其范围

给定一个简单的工厂:

编译器抱怨:

我对 OCaml 模块很陌生,不知道如何告诉编译器f是那种类型Factory.t

0 投票
1 回答
128 浏览

module - 将模块传递给其他模块

我正在尝试将 Irmin 与 MirageOS 一起使用,并且我正在努力处理所有这些模块。我查看了 Canopy 的来源,试图弄清楚应该如何使用 Irmin,我有这个:

从开始功能,我可以很好地使用 Store,设置并阅读 repo .. 我如何传递 Store ?由于所有这些类型都依赖于 start 的参数,我不能(或不知道如何)在其他任何地方定义这些模块,并且我在其他任何地方传递或定义 Store 的所有尝试都失败了,因为构造函数会逃避它们范围。我确实设法创建了自己的 store.ml 文件(就像在 Canopy 中一样),但它只是将问题转移到一个新模块,我仍然不知道如何传递它。

在树冠中,他们似乎只从 start 函数中使用 Store 模块,这对他们来说很好,但不是我想做的。

我正在尝试使用 Irmin,但我认为这不是 Irmin 问题,我可能只是对模块系统在 ocaml 中的工作方式非常错误。当我尝试将它传递给另一个函数或模块时,我最终会遇到错误,例如

这似乎合乎逻辑,但我不知道如何解决这个问题。

谢谢

0 投票
1 回答
260 浏览

module - 无法在递归函数中推断此打包模块的签名

我仍在试图弄清楚在使用 mirage 时如何拆分代码,它有无数的一流模块。我已经把我需要的一切都放在了一个又大又丑的Context模块中,以避免将十个模块传递给我的所有功能,一个就够痛苦了。

我有一个通过 tcp 接收命令的功能:

经过数小时的反复试验,我发现我需要添加(type a)“显式”type chan = a才能使其工作。看起来很难看,但它可以编译。但是,如果我想让该函数递归:

我通过了两次模块,第一次没问题,但在递归行上出现错误:

如果我尝试指定我得到的签名

似乎我不能使用整个(type chan = a)东西。如果有人可以解释正在发生的事情,以及理想的解决方法,那就太好了。我当然可以使用一段时间,但我宁愿最终理解这些该死的模块。谢谢 !

0 投票
4 回答
3903 浏览

scala - 什么(确切地说)是“头等舱”模块?

我经常读到一些编程语言对模块(OCaml、Scala、TypeScript[?])有“一等”支持,最近偶然发现一个关于 SO 的答案,在Scala 的显着特征中引用模块是一等公民。

我以为我非常了解模块化编程的含义,但在这些事件之后,我开始怀疑我的理解......

我认为模块没什么特别的,只是某些类的实例,它们充当迷你库。迷你库代码进入一个类,该类的对象是模块。您可以将它们作为依赖项传递给需要模块提供的服务的任何其他类,因此任何体面的 OOPL 都有一流的模块,但显然没有!

  1. 模块到底是什么?它与普通类或对象有何不同?
  2. (1)与我们都知道的模块化编程有什么关系(或不相关)?
  3. 一门语言拥有一流的模块究竟意味着什么?有什么好处?如果一种语言缺乏这样的特性,有什么缺点?
0 投票
1 回答
279 浏览

compiler-errors - 解压受类型变量约束的一流模块

我正在尝试编写一个基本上如下所示的函数:

也就是说,一个接受任何类型值的函数,以及一个包含一个或多个可以对该值进行操作的函数的关联模块。不幸的是,上面会让编译器抱怨

此打包模块的类型包含变量

但是,我发现如果我将它包装在一个 GADT 中,我仍然可以让它工作 1)创建'a一个存在和 2)提供从另一个参数化类型变量到存在的转换器:

GADT 本身并不麻烦1但我非常想避免使用该convert功能,因为它除了帮助编译器之外没有任何用途。这有可能吗?

完整示例/MCVE


1我实际上想要 GADT,因为我需要用不同的存在参数对模块进行参数化,这样我就可以将不同类型的模块放在一个列表中。但为简单起见,我从上面的第一个示例中省略了这一点。

0 投票
3 回答
181 浏览

generics - 如何从函数中返回一流模块嵌套类型的实例?

语境:

我正在尝试使用一流的模块在 OCaml 中实现诸如 OOP 可观察模式之类的东西。我有一个包含模块列表的项目,并希望通过观察来扩展它们而不进行更改。为了最大限度地减少代码重复,我创建了主题模块并计划将其用作此扩展的通用方式(在项目上下文中)的一部分。我声明了三种模块类型:

观察者:

可观察:

以及合并OBSERVEROBSERVABLE的SUBJECT

我实现的下一件事是主题模块。该模块的职责是将许多OBSERVER聚合为一个。当然,它们应该处理相同的事件类型,这就是我将“ Subject ”(Subject.Make)实现为仿函数的原因。

为了存储OBSERVER的一流模块的实例,并能够添加和删除(以任何顺序)它们,我使用Mapint作为(即subscr)。

从OBSERVER ( ) 中的发送签名可以看出,不仅需要存储OBSERVER的一流模块的实例,还需要存储它们的状态(“ OBSERVER.t ”的实例)。由于类型不同,我无法将所有状态存储在一个集合中。因此,我声明了模块类型PACK以将OBSERVER的一流模块的实例及其状态实例打包到PACK的实例中。val send : event -> t -> t

Subject的函数send在新状态和旧Observer模块中重新打包每个包。

测试主题并查看模块在没有更改的情况下通过观察扩展的外观 - 我创建了一些模块Acc

并在模块OAcc中使用观察功能对其进行了扩展,具有以下签名,即合并OBSERVABLE和原始Acc的模块类型

我实施了 OAcc,将观察责任委托给Subject,将主要责任委托给原始Acc

创建了一些“ OBSERVER模块”,它只是将操作打印到控制台中

最后,我创建了函数print_operations并测试了一切都按预期工作

调用后print_operations ();;我有以下输出

# print_operations ();;

1.添加(1);
2.添加(1);
3.添加(1);
1.乘法(2);
2.乘法(2);
3.乘法(2);
1.乘法(3);
3.乘(3);
1.添加(4);
3.添加(4);
1.添加(5);

- : 整数 = 90

当我们的一流模块观察者的逻辑完全基于副作用并且我们不需要它在Subject之外的状态时,一切正常。但是对于相反的情况,我没有找到任何关于如何从Subject中提取订阅观察者状态的解决方案。

例如,我有以下“ OBSERVER ”(在这种情况下,访问者多于观察者)

我可以将History的一等实例和它的一些初始状态订阅到OAcc,但我不知道如何将其提取回来。


我试图做的。我在OBSERVABLE中更改了unsubscribe的签名。在返回没有与提供的订阅关联的“ OBSERVER ”的“ OBSERVABLE ”状态之前,现在它返回此状态、未订阅的第一类模块和未订阅模块的状态的三倍。

前:

后:

OBSERVABLE是可编译的,但我无法实现它。以下示例显示了我的一项尝试。

结果,我有:

错误:此表达式的类型为 Pack.Observer.t
,但表达式应为 'a
类型。类型构造函数 Pack.Observer.t 将逃脱其范围

问题一:

是否可以使用此签名实现取消订阅?


它不起作用。我尝试了另一种解决方案。它基于取消订阅可以返回PACK的一流模块的实例的想法。我更喜欢前面的想法,因为它在Subject中将PACK的声明保持为私有。但目前的解决方案在寻找解决方案方面取得了更好的进展。

我将PACK模块类型添加到OBSERVABLE 中,并将取消订阅签名更改为以下内容。

将PACK添加到OAcc实现中,因为它的签名包括OBSERVABLE。另外,我重新实现了取消订阅OAcc

Subject的实现已经包含PACK,所以不需要添加它。只有取消订阅被重新实现。

最后,我创建了我将history_of_operations更改为测试解决方案

打电话后history_of_operations ();;我有错误

错误:此表达式的类型为 Pack.Observer.t
,但表达式应为 'a
类型。类型构造函数 Pack.Observer.t 将逃脱其范围

另外,我试过

错误:此表达式的类型为 Pack.Observer.t
,但表达式应为 History.t 类型

问题2:

如何从List.t类型的Pack中提取状态?


我更改了取消订阅的签名

并尝试在主题中重新实现取消订阅

错误:此表达式具有类型(模块 PACK)
,但表达式应为类型
(模块 PACK,类型为 Observer.t = t)

看起来 OCaml 有 3 个级别的类型抽象
1. 具体module A : sig type t = int end = struct ...
2. 抽象module A : sig type t end = struct ...
3. 打包到一流模块

问题 3:

是否可以存储具有(2) 抽象级别或能够将其恢复到(2) 抽象级别的第一类模块实例的嵌套类型?


标题中的问题:

如何从函数中返回一流模块嵌套类型的实例?


评论:

当然,可以通过使用可变状态来解决这个问题,但问题不在于。

最初的可编译源代码在这里

0 投票
1 回答
234 浏览

ocaml - 如何将打包为“类型”的“模块类型”解包回“模块类型”?

我们可以将模块打包为 value 并将其解包回模块(模块作为一等公民)。此外,我们可以将模块类型打包到类型,但是......是否可以从类型中解压缩模块类型?如果是 - 如何?如果不是 - 为什么?下面的草图显示了我的意思。

或者


补充说明:

那么我为什么要问这个问题。很多时候 Ocaml 无法推断出第一类模块实例的类型,因此应该对其进行注释。可以通过两种方式进行:

1) 通过签名

2) 按类型

常见的第二种方式更短且易于阅读,尤其是在签名 (.mli) 中。

我们从模块类型创建类型以简化代码阅读或在必要的情况下(例如当函子期望它时)。有时我只需要类型,但也必须声明模块类型,因为从模块类型约束新类型的支持是有限的 在此处输入图像描述

并且缺少从类型(绑定到模块类型)中约束新类型(绑定到模块类型)。

至于我,这种方式让模块更加一流。此外,它与实例和模块之间的关系是对称的(据我了解let x = (module X)let module X = (val x)也是绑定)。对称性——很好(例如它部分存在于函数和函子之间)。但正如我在这个地方看到的那样,OCaml 在模块语言和核心语言之间存在边界。我问“how”是因为有希望,问“why”是因为确定这个问题是在OCaml的设计过程中打开的,所以这个边界是基于一些决定和原因。

0 投票
1 回答
157 浏览

module - 如何在不知道元素类型的情况下创建一组元素?

我在尝试使用 Caml 的 Map/Set 东西时遇到了递归/相互引用模块定义的问题。我真的想要只适用于类型而不是模块的那些。我觉得应该可以使用一流的模块来做到这一点,但是我无法使语法正常工作。

我想要的签名是:

可能还包括其他Caml.Set功能。我对它如何工作的想法是这样的:

但由于多种原因,这不起作用。'a 没有暴露在正确的位置,我不能在定义 m 的同一记录中引用 mt 等。

有这样的版本吗?

添加有关我的用例的更多上下文:

我有两个模块,RegionTribe. Tribe需要访问 的很多接口Region,所以我目前正在创建Tribe一个仿函数,MakeTribe(Region : RegionT). Region大多数情况下不需要知道Tribe,但它确实需要能够存储Tribe.t代表居住在该地区的部落的可变集合。

所以,不知何故,我需要一个RegionT喜欢

我并不真正关心 , 的具体语法<tribe>,在此<tribes><region>只要完全构建的Tribe模块可以知道Region.get_local_tribes,等等,就会产生一个实际Tribe.t 的循环依赖问题是该类型在模块创建<tribe>之前不存在。Tribe到目前为止,我的想法一直是RegionT.t实际存在'a RegionT.t,然后Tribe可以简单地参考Tribe.t Region.t。如果我对保留一个<tribe> listinside感到满意,这一切都很好Region,但我希望它是一个集合。

根据以下示例代码,我觉得这应该是可能的:

在其接口中Example公开的只是一个类型和一个从该类型的两个实例到一个 int 的函数;为什么这比拥有一个'a -> 'a -> int具有相同事物的 更重要?

0 投票
1 回答
53 浏览

vba - 将变量从类模块传递到用户窗体

嘿,我正在尝试设计一个代码,其中许多命令按钮调用相同的用户窗体。我已经创建了类模块并让它工作,以便它们都调用用户窗体,但我需要从类模块传递到用户窗体初始化的按钮的名称。我已经尝试使用属性获取和公共功能,但无法使其正常工作。我要传递的变量是“ScreenShotCap”作为字符串任何人,谁能帮忙?

类模块代码

用户表单代码