2017-05-25 60 views
4

我想写一些数字代码,可以使用标量或向量(在这种情况下,分别来自DiffSharp D和DV类型)。有时候,我希望能够为使用,所以我已经定义了一个歧视工会为他们:运算符重载为歧视的联盟

type IBroadcastable = 
    | Scalar of D 
    | Vect of DV 

许多运营商都已经重载这两种类型的,所以使用它们IBroadcastable我写的代码添加像这样的联盟:

static member Exp x = 
    match x with 
     | Scalar x -> Scalar (exp x) 
     | Vect x -> Vect (exp x) 

这似乎很多余。有什么办法可以在联合体上使用运算符,而不必为它编写新的重载?或者我应该使用不同的模式(即不是歧视的工会)?什么,我想用这种类型的一个例子:

let ll (y: IBroadcastable) (theta: IBroadcastable) = y*theta-(exp theta) 

*-将有更复杂的行为(阵列广播),这是有意义的有来形容自己,但exp操作简单,如上。这需要是一个函数,因为我希望能够部分应用y参数,使用DiffSharp获取渐变,并且相对于theta参数使其最大化。

+0

我不明白你为什么需要这个工会。与仅在'D'或'DV'上使用操作员相比,它会给你带来什么,无论你现在手头有哪一个? –

+0

@FyodorSoikin我想写一个函数,其中一个参数可以是任何一种类型,并且它看起来像一个联合是通常的做法。注意:如果不清楚,我是一个相当新的F#程序员。 –

+0

你将如何使用该功能?它将如何实施?为什么你不能用这个实现来代替函数? –

回答

2

基本上,由于您定义了抽象,您需要根据抽象定义操作。这是一种代价,必须通过它在代码中其他地方提供的便利来抵消。

你可能想知道的是,如果F#会让你在你的特定情况下在样板上裁剪。除了使用function关键字外,其实并非如此,因为两个分支都在做着不同的事情:绑定变量x的类型是不同的,并且您将它们封装在不同的联合事例中。如果你真的做同样的事情,你可以把它写成这样,例如:

type DU = 
| A of float * float 
| B of float * string 
with 
    static member Exp = function 
     | A (b, _) 
     | B (b, _) -> exp b // only write the logic once 
1

你的样品功能ll实际上是更通用的 - 它可以在任何的工作,支持它使用的操作,甚至事那不是DDV。如果您在使用inline定义它,那么你将能够调用两个功能:

let inline ll y theta = y*theta-(exp theta) 

inline修改器可用于F#使用静态成员的限制,可以通过所需的成员在调用函数时被满足(不像具有正常的泛型函数,必须使用.NET运行时提供的函数进行编译)。

我希望这不适用于您的所有代码,因为您需要一些特定于DDV的操作,但没有通用的F#功能,例如exp。你实际上可以访问那些使用静态成员约束的东西,尽管这会变得有点多毛。

假设DDV值都有一个成员Foo返回string,你可以写:

let inline foo (x:^T) = 
    (^T : (member Foo : string) x) 

let inline ll y theta = y*theta-(exp theta)+foo y 
1

可以减少对样板做这样的事情:

type IBroadcastable = 
| Scalar of D 
| Vect of DV 

let inline private lift s v = function 
| Scalar d -> Scalar (s d) 
| Vect dv -> Vect (v dv) 

type IBroadcastable with 
    static member Exp b = lift exp exp b 
    static member Cos b = lift cos cos b 
    ... 

,如果你想支持二元运算符,你可以定义一个对应的lift2 - 但仔细考虑一下对于二进制歌剧的第一个参数是否有意义tor是Scalar的价值,第二个是Vect(反之亦然) - 如果不是,那么你的歧视联盟可能不是一个适当的抽象。