2017-01-03 77 views
0

我使用單片眼鏡,scala中的透鏡庫來重構代碼的出現代碼day 12如何在scala中使用單片眼鏡減少樣板文件

是否有可能改善這種代碼:

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

+1

我會用'index'代替當你想修改地圖中的值時,例如'at' '(State.mem composeLens at(r))。modify(_。map(_ + 1))' –

回答

-1

您可能需要使用第二種方法,因爲它分隔兩個字段的處理。 但是,功能不應按順序解釋(andThen),而應將它們合併爲PartialFunction s與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)) 
} 

UPDATE(在晏穆瓦桑後評論)

執行不得在用戶程序的無限循環的情況下終止。因此,而不是在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最後一行應與上面的代碼代替)

+0

指令不應該是'(State.mem compose可選索引(r))。modify(_ + 1)'而不是'由於跳轉(jnz)指令而執行。 –

+0

這裏有兩個方面。一個是模塊化 - 分別處理各種指令。這是通過'PartialFunction'實現的。另一方面是正常指令(執行和指針前進)的兩個步驟的順序運行。這兩個方面都可以在'processInstruction3'中正確處理。在'processInduct2''(ptr和Then mem)''Jnz'的情況下,它也將被第二個模式匹配塊處理(幸運的是沒有其他類似的指令,它將通過默認情況)。 –