【发布时间】:2017-02-16 18:03:19
【问题描述】:
问题
第一种方法
如果想拥有
trait Distance extends ((SpacePoint, SpacePoint) => Double)
object EuclideanDistance extends Distance {
override def apply(sp1: SpacePoint, sp2: SpacePoint): Double = ???
}
trait Kernel extends (((Distance)(SpacePoint, SpacePoint)) => Double)
object GaussianKernel extends Kernel {
override def apply(distance: Distance)(sp1: SpacePoint, sp2: SpacePoint): Double = ???
}
但是object GaussianKernel extends Kernel 的apply 并不是trait Kernel 的apply 的例外override。
第二种方法 - 编辑: 事实证明这是可行的...
或者我可以写
trait Kernel extends ((Distance) => ( (SpacePoint, SpacePoint) => Double))
object GaussianKernel extends Kernel {
override def apply(distance: Distance): (SpacePoint, SpacePoint) => Double =
(sp1: SpacePoint, sp2: SpacePoint) =>
math.exp(-math.pow(distance(sp1, sp2), 2) / (2))
}
但我不确定这是在柯里化......
编辑: 事实证明,我可以以柯里化的方式使用第二种方法。我认为这正是典型的柯里化,只是没有语法糖。
想法的解释
想法是这样的:对于我的算法,我需要一个Kernel。这个内核计算空间中两个向量的度量——这里是SpacePoints。为此,内核需要一种方法来计算两个SpacePoints 之间的距离。距离和内核都应该是可交换的(open-closed principle),因此我将它们声明为特征(在 Java 中我将它们声明为接口)。这里我使用Euclidean Distance(未显示)和Gaussian Kernel。为什么是咖喱?稍后在使用这些东西时,distance 对于所有测量值都会或多或少相同,而SpacePoints 会一直变化。再次,努力坚持开闭原则。因此,在第一步中,我希望GaussianKernel 被预先配置(如果你愿意的话)一个距离并返回一个Function 可以稍后在程序中使用SpacePoints 提供(我确定代码错误,只是为了让您了解我的目标):
val myFirstKernel = GaussianKernel(EuclideanDistance)
val mySecondKernel = GaussianKernel(FancyDistance)
val myThirdKernel = EpanechnikovKernel(EuclideanDistance)
// ... lots lof code ...
val firstOtherClass = new OtherClass(myFirstKernel)
val secondOtherClass = new OtherClass(mySecondKernel)
val thirdOtherClass = new OtherClass(myThirdKernel)
// ... meanwhile in "OtherClass" ...
class OtherClass(kernel: Kernel) {
val thisSpacePoint = ??? // ... fancy stuff going on ...
val thisSpacePoint = ??? // ... fancy stuff going on ...
val calculatedKernel = kernel(thisSpacePoint, thatSpacePoint)
}
问题
- 如何建立我的特质?
- 由于
distance对于不同的GaussianKernels 可能不同 -GaussianKernel应该是一个类而不是一个对象吗? - 我应该部分应用
GaussianKernel而不是currying吗? - 我的方法是不是不好,
GaussianKernel应该是一个在字段中存储distance的类?
【问题讨论】:
-
我不明白你在做什么。为什么距离是一个特征,它扩展了一个接受一个元组并返回一个双精度的函数?你想要完成什么(你所追求的用例是什么)?
-
@BrianPendleton:有帮助吗?
-
你不能扩展 Function1 并期望它会“知道”你想要柯里化,类型已经定义。但是你为什么不使用一种 DI 给内核一个距离函数呢?一个简单的构造函数参数可以工作。或者你也可以使用蛋糕模式。
-
@LomigMégard:
Function1的类型已经定义是什么意思?我不是通过写(((Distance)(SpacePoint, SpacePoint)) => Double)来定义类型吗? -
@LomigMégard:使用“一种 DI 为内核提供距离函数”正是我想要做的。只是我试图 a) 不将其提供给构造函数,而是将其提供给
apply,以便稍后我可以将整个事物用作函数 b) 我试图将它与柯里化结合起来。据我了解,这和蛋糕模式(相当酷的顺便说一句)都是 DI。在coderwall.com/p/t_rapw/… 中,它们被认为同样出色,只是风格不同。
标签: scala