我可以将类型作为参数传递给这个函数吗?

Posted

技术标签:

【中文标题】我可以将类型作为参数传递给这个函数吗?【英文标题】:Can I pass a type as a parameter to this function? 【发布时间】:2017-05-26 18:52:25 【问题描述】:

以下代码,大部分抄自

http://accord-framework.net/docs/html/T_Accord_MachineLearning_VectorMachines_Learning_SequentialMinimalOptimization.htm

工作正常。

module SVMModule

open Accord.MachineLearning
open Accord.MachineLearning.VectorMachines
open Accord.MachineLearning.VectorMachines.Learning
open Accord.Statistics.Kernels
open Accord.Math.Optimization.Losses

// open MathNet.Numerics.LinearAlgebra.Matrix

let inputs = [| [| 0.; 0. |]; [| 0.; 1. |]; [| 1.; 0. |]; [| 1.; 1. |] |]
let xor = [| 0; 1; 1; 0 |]
/// Creates and trains a Support Vector Machine given inputs and outputs.
/// The kernel can be Linear, Gaussian, or Polynomial.
/// The default tolerance is 1e-2.
let train (C: float) (tol: float) (inputs: float [] []) =
    let learn = SequentialMinimalOptimization<Gaussian>()

    learn.UseComplexityHeuristic <- true
    learn.UseKernelEstimation <- true
    if C >= 0. then learn.Complexity <- C
    if tol > 0. then learn.Tolerance <- tol

    let svm = learn.Learn(inputs, xor)
    svm

let svm = train 0.5 1e-2 inputs
let prediction = svm.Decide inputs

printfn "SVM_0 Prediction: %A" prediction

我想实现train 的多态版本,类似于

let train (kernel: string) (C: float) (tol: float) (inputs: float [] []) =
    let learn =
        if kernel = "Gaussian" then 
           SequentialMinimalOptimization<Gaussian>()
        else
           SequentialMinimalOptimization<Linear>()
    // More code

这不起作用,因为if 表达式必须在其所有分支中返回相同类型的对象。

我想知道是否有办法将LinearGaussian 作为类型传递给train(这些确实是类型),这样我就不必为每种类型编写一个火车函数(trainGaussiantrainLinear)。 Akso,即使我不厌其烦地编写这些单独的函数,我想根据用户的选择在运行时调用它们也很困难,因为 if 语句的同样问题会引起它的丑陋。

我已经使用接口在F# 中实现了多态性,但使用的是我自己构建的类。这些类位于Accord.NET 中,即使它们继承自基类,我也无法处理类型问题并实现多态性。

感谢您的任何建议。

【问题讨论】:

【参考方案1】:

't 之类的类型参数简单地替换具体类型Gaussian 应该很简单(并且可以选择将其作为显式类型参数添加到train)。这样做时,我已经稍微清理了您现有的代码:

let train<'t> (C: float) (tol: float) (inputs: float [] []) =
    let learn = SequentialMinimalOptimization<'t>(UseComplexityHeuristic = true, UseKernelEstimation = true)
    if C >= 0. then learn.Complexity <- C
    if tol > 0. then learn.Tolerance <- tol

    learn.Learn(inputs, xor)

然后在调用点,编译器需要通过某种方式知道要使用什么类型,或者通过显式传递它:

let svm = train<Gaussian> 0.5 1e-2 inputs

或者通过依赖类型推断来从程序的另一部分传递类型:

let svm:Gaussian = train 0.5 1e-2 inputs

【讨论】:

谢谢。这看起来很有希望。但是,当我将您的代码复制到我的 .fsx 文件中时,我在 SequentialMinimalOptimization 下得到一条红色波浪线和消息 A type parameter is missing a constraint 'when 't :&gt; IKernel&lt;float []&gt;'。我还缺少什么吗? @Soldalma - 抱歉,我猜SequentialMinimalOptimization&lt;_&gt; 的类型参数有一个约束,如果您添加显式类型参数(即您需要定义它是train&lt;'t when 't :&gt; IKernel&lt;float []&gt;&gt;)。另一方面,如果你在定义中省略了参数(所以它只是let train (C:float) ...),那么我相信应该在你不做任何额外工作的情况下推断出约束。 再次感谢。两种选择都有效,尽管我很惊讶您可以从函数签名中删除类型并将其保留在函数体中。继续前进,我遇到了另一个障碍。如果类型为线性,则语句 learn.UseKernelEstimation &lt;- true 会导致运行时错误。有没有办法使用取决于类型的 ifmatch 语句跳过它?

以上是关于我可以将类型作为参数传递给这个函数吗?的主要内容,如果未能解决你的问题,请参考以下文章

我可以将类引用作为参数传递给 VB Net 中的函数吗?

如何将带有 args 的成员函数作为参数传递给另一个成员函数?

将对象作为参数传递给函数

我可以将数据集作为参数传递给流分析作业中的 AzureML 实验吗?

我可以通过 add_action 将参数传递给我的函数吗?

将一个函数的所有参数传递给另一个函数