由于 Apocalisp 已经 提到 我要引用的内容,所以我将讨论代码。你说这只是简单的乘法,但我没有看到这一点——它引用了至少三个重要的在外部定义的方法:order
、states
和 M.log
。我可以推断出 order
是一个 Int
,而 states
返回一个函数,该函数接受一个 List[T]
和一个 T
并返回一个 Double
。
还有一些奇怪的事情发生...
def logLikelihood(seq: Iterator[T]): Double = {
val sequence = seq.toList
sequence
只被用来定义seqPos
,那么为什么要这样做?
val stateSequence = (0 to order).toList.padTo(sequence.length,order)
val seqPos = sequence.zipWithIndex
def probOfSymbAtPos(symb: T, pos: Int) : Double = {
val state = states(stateSequence(pos))
M.log(state( seqPos.map( _._1 ).slice(0, pos).takeRight(order), symb))
实际上,您可以在这里使用
sequence
代替
seqPos.map( _._1 )
,因为它只是撤销了
zipWithIndex
。此外,
slice(0, pos)
就是
take(pos)
。
}
val probs = seqPos.map( i => probOfSymbAtPos(i._1,i._2) )
probs.sum
}
现在,由于缺少方法,很难确定这个应该如何以函数式风格编写。保留神秘的方法将产生以下结果:
def logLikelihood(seq: Iterator[T]): Double = {
import scala.collection.immutable.Queue
case class State(index: Int, order: Int, slice: Queue[T], result: Double)
seq.foldLeft(State(0, 0, Queue.empty, 0.0)) {
case (State(index, ord, slice, result), symb) =>
val state = states(order)
val partial = M.log(state(slice, symb))
val newSlice = slice enqueue symb
State(index + 1,
if (ord == order) ord else ord + 1,
if (queue.size > order) newSlice.dequeue._2 else newSlice,
result + partial)
}.result
}
我怀疑state
/M.log
的东西也可以成为State
的一部分。我写成这样后,注意到了其他的优化。你使用的滑动窗口让我想起了sliding
。
seq.sliding(order).zipWithIndex.map {
case (slice, index) => M.log(states(index + order)(slice.init, slice.last))
}.sum
这将只从第order个元素开始,因此需要进行一些适应。不过并不难。所以让我们再次重写它:
def logLikelihood(seq: Iterator[T]): Double = {
val sequence = seq.toList
val slices = (1 until order).map(sequence take) ::: sequence.sliding(order)
slices.zipWithIndex.map {
case (slice, index) => M.log(states(index)(slice.init, slice.last))
}.sum
}
我希望能够看到
M.log
和
states
... 我敢打赌我可以将那个
map
转化为
foldLeft
并且不再需要这两个方法。而且我怀疑由
states
返回的方法可以接受整个切片而不是两个参数。
不过...还不错,对吧?