我可以将类型作为参数传递给这个函数吗?
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
表达式必须在其所有分支中返回相同类型的对象。
我想知道是否有办法将Linear
或Gaussian
作为类型传递给train
(这些确实是类型),这样我就不必为每种类型编写一个火车函数(trainGaussian
和trainLinear
)。 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 :> IKernel<float []>'
。我还缺少什么吗?
@Soldalma - 抱歉,我猜SequentialMinimalOptimization<_>
的类型参数有一个约束,如果您添加显式类型参数(即您需要定义它是train<'t when 't :> IKernel<float []>>
)。另一方面,如果你在定义中省略了参数(所以它只是let train (C:float) ...
),那么我相信应该在你不做任何额外工作的情况下推断出约束。
再次感谢。两种选择都有效,尽管我很惊讶您可以从函数签名中删除类型并将其保留在函数体中。继续前进,我遇到了另一个障碍。如果类型为线性,则语句 learn.UseKernelEstimation <- true
会导致运行时错误。有没有办法使用取决于类型的 if
或 match
语句跳过它?以上是关于我可以将类型作为参数传递给这个函数吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何将带有 args 的成员函数作为参数传递给另一个成员函数?