运算符重载为歧视的联盟
我想写一些数字代码,可以使用标量或向量(在这种情况下,分别来自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参数使其最大化。
基本上,由于您定义了抽象,您需要根据抽象定义操作。这是一种代价,必须通过它在代码中其他地方提供的便利来抵消。
你可能想知道的是,如果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
你的样品功能ll
实际上是更通用的 - 它可以在任何的工作,支持它使用的操作,甚至事那不是D
或DV
。如果您在使用inline
定义它,那么你将能够调用两个功能:
let inline ll y theta = y*theta-(exp theta)
的inline
修改器可用于F#使用静态成员的限制,可以通过所需的成员在调用函数时被满足(不像具有正常的泛型函数,必须使用.NET运行时提供的函数进行编译)。
我希望这不适用于您的所有代码,因为您需要一些特定于D
和DV
的操作,但没有通用的F#功能,例如exp
。你实际上可以访问那些使用静态成员约束的东西,尽管这会变得有点多毛。
假设D
和DV
值都有一个成员Foo
返回string
,你可以写:
let inline foo (x:^T) =
(^T : (member Foo : string) x)
let inline ll y theta = y*theta-(exp theta)+foo y
可以减少对样板做这样的事情:
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
(反之亦然) - 如果不是,那么你的歧视联盟可能不是一个适当的抽象。
我不明白你为什么需要这个工会。与仅在'D'或'DV'上使用操作员相比,它会给你带来什么,无论你现在手头有哪一个? –
@FyodorSoikin我想写一个函数,其中一个参数可以是任何一种类型,并且它看起来像一个联合是通常的做法。注意:如果不清楚,我是一个相当新的F#程序员。 –
你将如何使用该功能?它将如何实施?为什么你不能用这个实现来代替函数? –