如何在scala中使用单片眼镜减少样板
我已经使用scala中的镜头库monocle重构了我的代码,以迎接代码的出现 是否可以改进此代码:如何在scala中使用单片眼镜减少样板,scala,lenses,monocle-scala,Scala,Lenses,Monocle Scala,我已经使用scala中的镜头库monocle重构了我的代码,以迎接代码的出现 是否可以改进此代码: type Register = String type Mem = Map[String, Int] @Lenses case class State(mem: Mem, pointer: Int) def processInstruction(instructions: Seq[Instruction]): State => State = { s =>
type Register = String
type Mem = Map[String, Int]
@Lenses
case class State(mem: Mem, pointer: Int)
def processInstruction(instructions: Seq[Instruction]): State => State = { s =>
(instructions(s.pointer) match {
case Inc(r) =>
State.pointer.modify( _ + 1) andThen (State.mem composeLens at(r)).modify(_.map(_ + 1))
case Dec(r) =>
State.pointer.modify( _ + 1) andThen (State.mem composeLens at(r)).modify(_.map(_ - 1))
case CpyInt(v, to) =>
State.pointer.modify( _ + 1) andThen (State.mem composeLens at(to)).set(Some(v))
case CpyReg(from, to) =>
State.pointer.modify( _ + 1) andThen (State.mem composeLens at(to)).set(Some(s.mem(from)))
case Jnz(r, v) => if (r != "1" && s.mem(r) == 0)
State.pointer.modify( _ + 1)
else
State.pointer.modify( _ + v )
}).apply(s)
}
这里是另一个尝试,分离每个字段的修改
def processInstruction2(instructions: Seq[Instruction]): State => State = { s =>
val ptr = instructions(s.pointer) match {
case Jnz(r, v) if !(r != "1" && s.mem(r) == 0) => State.pointer.modify(_ + v)
case _ => State.pointer.modify(_ + 1)
}
val mem = instructions(s.pointer) match {
case Inc(r) => (State.mem composeLens at(r)).modify(_.map(_ + 1))
case Dec(r) => (State.mem composeLens at(r)).modify(_.map(_ - 1))
case CpyInt(v, to) => (State.mem composeLens at(to)).set(Some(v))
case CpyReg(from, to) => (State.mem composeLens at(to)).set(Some(s.mem(from)))
case _ => identity[State]
}
(ptr andThen mem)(s)
}
还有一个问题:有没有一种方法可以将Map.withDefaultValue
与monocle一起使用
完整代码如下:您可能希望使用第二种方法,因为它将两个字段的处理分开。 但是,函数不应按顺序解释(
和
),而应将它们作为部分函数
s与或LSE
组合
def processInstruction3(instructions: Seq[Instruction]): State => State = {
val ptr: PartialFunction[Instruction, State => State] = {
case Jnz(r, v) =>
State.pointer.modify(_ + v)
}
val incPointer: State => State = State.pointer.modify( _ + 1)
def reg(r: String): Lens[State, Option[Int]] = State.mem composeLens at(r)
val mem: PartialFunction[Instruction, State => State] = {
case Inc(r) => reg(r).modify(_.orElse(Option(0)).map(_ + 1))
case Dec(r) => reg(r).modify(_.orElse(Option(0)).map(_ - 1))
case CpyInt(v, to) => reg(to).set(Some(v))
case CpyReg(from, to) => s => reg(to).set(reg(from).get(s))(s)
}
val interpreter = ptr orElse (mem andThen (_ andThen incPointer))
s => instructions.foldLeft(s)((s, i) => interpreter(i)(s))
}
更新(在Yann Moisan评论之后)
如果用户程序中存在无限循环,则执行可能不会终止。因此,我们需要一些递归函数,而不是foldLeft
,它将通过指针提取下一条指令:
@tailrec
def loop(s: State): State = {
if(s.pointer>=instructions.length)
s
else {
val instruction = instructions(s.pointer)
val nextState = interpreter(instruction)(s)
loop(nextState)
}
}
loop _
(应将
processInstruction3
的最后一行替换为上述代码)由于跳转(jnz)指令,指令不应按顺序执行。一种是模块化——分别处理各种指令。这是通过PartialFunction
实现的。另一个方面是正常指令(执行和指针前进)的两个步骤的顺序运行。这两个方面在过程说明3
中都得到了正确处理。在processInstruction2
(ptr和THEN mem)
中,在Jnz
的情况下,它也将由第二个模式匹配块处理(幸运的是没有其他类似的指令,它将通过默认情况)。当您想要修改映射内部的值时,我将使用索引而不是at
,例如(State.mem compose可选索引(r))。修改(+1)
而不是(State.mem composeLens at(r))。修改(+1))