【发布时间】:2018-03-04 11:13:05
【问题描述】:
这是一个“现实生活”的面向对象设计问题。我正在使用 Scala,并且对特定的 Scala 解决方案感兴趣,但我绝对愿意听取一般的想法。
我正在实施一个分支定界组合优化程序。该算法本身很容易实现。对于每个不同的问题,我们只需要实现一个类,该类包含有关搜索允许的邻居状态是什么、如何计算成本以及可能是什么下限等信息...
我还希望能够尝试不同的数据结构。例如,存储逻辑公式的一种方法是使用简单的整数列表。这表示一组子句,每个整数都是一个文字。但是,如果我们执行“双字面观察列表”之类的操作,并且通常存储一些有关公式的额外信息,我们可以获得更好的性能。
这一切都意味着这样的事情
object BnBSolver[S<:BnBState]{
def solve(states: Seq[S], best_state:Option[S]): Option[S] = if (states.isEmpty) best_state else
val next_state = states.head
/* compare to best state, etc... */
val new_states = new_branches ++ states.tail
solve(new_states, new_best_state)
}
class BnBState[F<:Formula](clauses:F, assigned_variables) {
def cost: Int
def branches: Seq[BnBState] = {
val ll = clauses.pick_variable
List(
BnBState(clauses.assign(ll), ll :: assigned_variables),
BnBState(clauses.assign(-ll), -ll :: assigned_variables)
)
}
}
case class Formula[F<:Formula[F]](clauses:List[List[Int]]) {
def assign(ll: Int) :F =
Formula(clauses.filterNot(_ contains ll)
.map(_.filterNot(_==-ll))))
}
希望这不是太疯狂、错误或令人困惑。这里的整个问题是,公式中的这个assign 方法通常只采用将要分配的当前文字。但是,对于两个字面量的观察列表,您正在做一些懒惰的事情,需要您稍后知道之前分配了哪些字面量。
解决此问题的一种方法是,您只需将先前分配的文字列表保留在数据结构中,也许作为私人事物。使其成为一个自立的惰性数据结构。但是这个先前分配的列表实际上是任何使用公式类的人都可以自然获得的东西。因此,如果有必要,让使用它的人每次assign 时只提供列表是有意义的。
这里的问题是我们现在不能有一个抽象的Formula 类,它只声明一个assign(ll:Int):Formula。正常情况下是可以的,但是如果这是一个两字面的监视列表公式,它实际上是一个assign(literal: Int, previous_assignments: Seq[Int])。
从使用它的类的角度来看,这还不错。但是,我们如何编写可以采用所有这些不同版本的Formula 的通用代码呢?由于签名的剧烈变化,它不能简单地是一个抽象的方法。我们也许可以强制用户总是提供完整的赋值变量,但这也是一种谎言。怎么办?
如果我写下某种适配器方法,该方法知道从哪里获取以前的任务,那么监视列表类就会变成一种常规的assign(Int) 类......我在想也许implicit 我们可以做饭。
【问题讨论】:
-
我发现你的问题有点令人困惑。我的感觉是,您将算法的许多问题与(再次)Scala 的太多问题混为一谈。
-
公式是否接受类型参数?
-
Btw solve 不会编译。
标签: scala oop inheritance abstract-class