【问题标题】:Is it possible to create a polymorphic variant type dynamically using modules?是否可以使用模块动态创建多态变体类型?
【发布时间】:2018-12-01 20:08:55
【问题描述】:

我正在尝试整理和重用我的 reasonML 代码。我的模型模块类型如下所示:

module Diet = {

  type schemaType = [`DietSchema];
  type idType = [`DietId(UUID.t)];

  let schema = `DietSchema;
  type idAsType('a) = [> | idType] as 'a;     
};

module Ingredient = {
  type schemaType = [`IngredientSchema];
  type idType = [`IngredientId(UUID.t)];

  let schema = `IngredientSchema;
  type idAsType('a) = [> | idType] as 'a;
};

module Restriction = {
  type schemaType = [`RestrictionSchema];
  type idType = [`RestrictionId(UUID.t)];

  let schema = `RestrictionSchema;
  type idAsType('a) = [> | idType] as 'a;
};

我想从idTypes 和schemaTypes 生成一个类型和函数。

例子是:

type modelIdType = [
  | Diet.idType
  | Restriction.idType
  | Ingredient.idType
];

type schemaType = [
  | Diet.schemaType
  | Restriction.schemaType
  | Ingredient.schemaType
];

let modelIdToIdFunction = (recordIdType): (schemaType, UUID.t) =>
  switch (recordIdType) {
  | `DietId(uuid) => (Diet.schema, uuid)
  | `RestrictionId(uuid) => (Restriction.schema, uuid)
  | `IngredientId(uuid) => (Ingredient.schema, uuid)
  };

所以我尝试使用函子来构造一个模块,将每个模式通过

module Diet : SchemaType = {
  /* ... */
};

module type SchemaType {
  type schemaType;
  type idType;

  let schema: [> schemaType];
  type idAsType('a) = [> | idType] as 'a;
};

module ProcessSchema = (
  Schema : SchemaType,
  PrevFullSchema : FullSchema
) : (FullSchema) => {
  type id = [> Schema.idType' | PrevFullSchema.id'('a)]  as 'a;
  /* type id = [PrevFullSchema.openId(PrevFullSchema.id) | Schema.idType]; */
  /* type schema = [PrevFullSchema.schema | Schema.schema]; */
  /* type openSchema = [PrevFullSchema.schema | Schema.schema]; */
};

上面的代码不起作用。我在将模块类型添加到顶部的模型模块时遇到问题。我还尝试通过SchemaType 模块类型,但一直点击The type idType is not a polymorphic variant type,当我希望每个模型具有不同的多态变量类型时。

总的来说,我想知道是否可以创建一个可以使用模块和仿函数创建或扩展的多态变体类型?

如果不是,是否可以使用“模块列表”构造多态变体类型?

谢谢

【问题讨论】:

  • 这“显然”不起作用的方式是什么?它不能编译,但那是因为缺少几个定义,而且不清楚你要做什么,或者你遇到了什么问题。可以发minimal reproducible example吗?
  • 答案可能是否定的。动态创建类型不是静态类型语言通常可以做的事情。 “静态”表示类型在编译时检查,“动态”表示它们在运行时检查。如果您可以在检查完成后创建类型,那将不是很安全。但也许你在这里用不同的意思使用“动态”?
  • 是的,上面的例子不能编译,我猜它可能没有用。这是尝试构建一个为多态变体生成类型的函子。我想我也用错了词。 “动态”我想我的意思是“可扩展”。我想通过添加更多的多态变体来扩展类型。
  • 在什么时候?你打算怎么处理他们?多态变体是结构性的,所以你不能真正“扩展”它们。当你给它一个名字时,它实际上只是右侧类型的别名。多态变体也支持子类型化,因此您可以指定一个多态变体类型,上面写着“至少这些构造函数”:[> `this | `that],但这意味着一个类型变量,即它实际上是 [> `this | `that] as 'a
  • 还有extensible variants,它更像是普通的变体,但是你必须包含一个通配符模式,这意味着你失去了穷举检查。

标签: ocaml variant strong-typing reason polymorphic-variants


【解决方案1】:

早在 2002 年就有人问过类似的问题。据一位 OCaml 语言开发人员称,不可能像这样动态扩展多态变体类型:https://caml-list.inria.narkive.com/VVwLM96e/module-types-and-polymorphic-variants。相关位:

函子定义被拒绝,因为 “类型 M.t 不是多态变体类型” 有解决办法吗?

我不知道。多态变体扩展仅适用于已知 封闭的变体类型,否则它不会是健全的。

这篇文章的其余部分有一个建议,归结为在不同标签内捕获新的变体类型,但同样不适用于您使用仿函数动态“添加”类型的用例。

【讨论】:

    【解决方案2】:

    对于这些类型,您可以使用可扩展的变体类型。但是对于给定模块列表的 modelIdToIdFunction 函数,我认为您只能通过列表进行搜索,这将无法扩展。

    您应该使用每个模块的 ID 扩展 uuid,以便您可以创建一个从 module_id 到列表中的模块的查找表,以便快速访问。

    【讨论】:

    • 我还没来得及实施,但您似乎是正确的可扩展变体类型似乎是解决方案。稍后我将更新我对SchemaTypeProcessSchema 的实现,或者如果有人可以向我展示它们的外观,我会接受。我会把这个给你,因为我不想浪费赏金点。谢谢
    猜你喜欢
    • 2020-08-06
    • 2020-08-06
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多