f# - F# 中的惯用构造函数

标签 f# inline

我从一个小的 OpenGL 包装器开始,但遇到了一个小问题。我通常用这样的记录创建我的数据

type Shader = 
    { Handle : int }
    static member Create filepath stype = 
        let h = loadshader filepath stype
        { Handle = h }

type VertexShader = 
    { shader : Shader }
    static member Create path = 
        { shader = Shader.Create path ShaderType.VertexShader }

type FragmentShader = 
    { shader : Shader }
    static member Create path = 
        { shader = Shader.Create path ShaderType.FragmentShader }

我总是使用带有非元组函数的静态构造函数。但现在我想要另一种类型,我想有可选参数。


type VAO = 
    { Handle : int }

    static member Create vboList ?ibo =
     ........

问题是,这对于非元组函数似乎是不可能的,我不想将我的 Create 方法与元组和非元组函数混合。

我想知道我是否一开始就编写了惯用的 F# 代码。你会如何处理这个“问题”?

最佳答案

你是对的——如果你想为一个方法定义可选参数,你需要以元组形式定义参数。您可以解决此问题的一种方法是移动您的 Create 的实现。方法转换为私有(private)方法(并将其重命名,例如,改为 CreateImpl ),然后重新定义 Create作为一个重载方法,它将简单地分派(dispatch)给实现。例如:

type VAO =
    { Handle : int }

    static member private CreateImpl (vboList, ibo : _ option) =
        failwith "Not implemented."

    static member Create vboList =
        VAO.CreateImpl (vboList, None)

    static member Create (vboList, ibo) =
        VAO.CreateImpl (vboList, Some ibo)

另一种方法是定义一个模块(它需要放置在您的 VAO 类型的定义之下),它定义了“包装”静态 VBO.Create(...) 的柯里化(Currying)函数。方法。这将起作用,但是您决定声明 Create 的参数。 (即,使用具有元组样式参数声明和可选参数的单个方法,或使用上述重载方法)。例如,如果你不使用我的重载方法,并决定只定义 Createstatic member Create (vboList, ?ibo) :
// The [<CompilationRepresentation>] attribute is necessary here, because it allows us to
// define a module which has the same name as our type without upsetting the compiler.
// It does this by suffixing "Module" to the type name when the assembly is compiled.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix>]
module VAO =
    let create (vboList : _ list) =
        VAO.Create vboList

    let createWithIndex vboList ibo =
        VAO.Create (vboList, ibo)

这些模块函数非常简单,因此它们很可能会被 F# 编译器自动内联,并且您不会为它们支付任何运行时成本。如果在 Release 中编译模式,检查程序集的 IL 并发现不是这种情况,然后您可以添加 inline函数定义的关键字以强制它们被内联。 (最好不要强制内联,除非您进行基准测试并确定它提供了真正的性能提升。)

一个提示,与您关于可选参数的问题无关——考虑将至少一些类型重新定义为结构而不是 F# 记录。记录类型被编译成类(即引用类型),因此您无缘无故地支付额外的间接成本;将它们定义为结构将消除这种间接性并为您的应用程序提供更好的性能。更好的是,如果您能够重用现有的 OpenGL 包装库之一,例如 OpenTKOpenGL4Net .

关于f# - F# 中的惯用构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21513494/

相关文章:

f# - 如何总结 seq<type> 上的成员?

asp.net-core - Cookie认证: How to access a returning user

css - 如何将一些div排成一行?

c++ - LNK2001 只有一些内联函数没有解决?

go - 不内联简单函数

perl - 为什么在使用 Moose 时覆盖 new 是 "very bad practice"?

f# - 来自类型提供程序 (XmlProvider) 的约束类型

f# - 如何让在一个进程上运行的参与者向在单独进程上运行的另一个参与者发送消息?

f# - 使用 FParsec 从大部分自由格式的文本中挑选 block

c++ - ‘t’ 声明中的两种或多种数据类型