我通过使用单片机(scala中的镜头库)重构了我的day 12代码出现代码。
是否可以改进此代码:
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
用于单片眼镜?
完整代码在此处:https://gist.github.com/YannMoisan/b8ba25afc041d88706545527d9ec1988
答案 0 :(得分:-1)
您可能希望使用第二种方法,因为它将两个字段的处理分开。
但是,不应按顺序解释函数(andThen
),而应将它们组合为PartialFunction
和orElse
。
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
的最后一行应替换为上面的代码)