generics - 再次出现 F# 中(非)通用模块的问题

标签 generics module f#

我试图构建的是一个通用的抽象语法树。我假设我有一组固定的语法结构,并且为每个结构定义了一个 F# 类型。然而,例如标识符名称和表达式应保持开放(通用)。因此,代码将类似于:

module GAST =
    type Declaration<'Name, 'Expr> = 
    {
        id: 'Name
        initialValue: 'Expr
    }

    type Loop<'Name, 'Expr> =
    {
        condition: 'Expr
        body: Statement<'Name, 'Expr> list
    }

    and Statement<'Name, 'Expr> = 
    | Declaration of Declaration<'Name, 'Expr>
    ...
    | Loop of Loop<'Name, 'Expr>
    ...

您看到了问题:我有很多类型,全部由 'Name'Expr 参数化。当我想将通用 AST“实例化”为特定 AST 时,我必须编写一个新模块,在其中实例化每个单独的类型:

module SpecificAST =
    type Name = string
    type Expr = | Name of Name | Const of int | Addition of Expr * Expr

    type Declaration = GAST.Declaration<Name, Expr>
    type Loop = GAST.Loop<Name, Expr>
    type Statement = GAST.Statement<Name, Expr>

这看起来有很多代码重复,并且需要一个可以将类型作为参数传递的模块之类的东西,因为我真的只想要类似的东西

module SpecificAST = GAST<Name, Expr>

上面的情况在 F# 中是不可能的。搜索时我发现Is it possible to pass parameters to F# modules?但问题有所不同。 只有一种类型定义,但该类型函数的行为是参数化的,这可以通过将记录类型转换为类并在实例化时将行为作为参数传递来解决.

我还看到了Can ML functors be fully encoded in .NET (C#/F#)?但我不知道那里的各种链接对我有什么帮助。

所以我的问题是这样的:给定许多具有相同类型参数的泛型类型。我可以一次实例化所有内容,但避免实例化模块中出现可怕的代码重复吗?

最佳答案

我认为您所拥有的解决方案是您使用当前构建问题的方式对 F# 所能实现的最佳解决方案 - F# 没有 ML 仿函数,并且没有模拟它们的通用方法。

也就是说,如果有另一种构建问题的方法可以让您以更好的方式解决问题,我不会感到惊讶。您的最小示例足以看出您无法使用 F# 模拟 ML 仿函数,但它没有提供替代解决方案的足够详细信息:

  • 您计划构建多少个特定 AST?您的示例只有一个,但即使您有三个,复制代码也可能比引入不会让您重用太多的抽象更容易。

  • 您想对共享类型做什么?是否有一些函数适用于所有具体 AST?也许还有另一种方法可以让您在没有 ML 风格仿函数的情况下重用此功能。

所以,我认为您的问题的答案是您的解决方案是您能做的最好的解决方案,但如果您提供有关其动机的更多信息,可能会有更好的 F# 设计。

关于generics - 再次出现 F# 中(非)通用模块的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46466264/

相关文章:

f# - F# 中的模块值不会被初始化。为什么?

javascript - require.js 有时不触发回调函数

f# - 以乘法优先级解析 "x y z"

F# 相交两个列表

f# - 在 FParsec 中解析简单类型

java - 为什么通配符类型参数不在自引用类型的包装器的范围内

c# - 类型约束 C# 泛型的无效转换

c++ - 什么是模块

c# - java和c#中泛型的语法差异

c# - 暴露泛型重载的接口(interface)。如何在这里干燥?