2017-01-03 10 views
0

스칼라의 렌즈 라이브러리 인 monocle을 사용하여 코드가 출현함에 따라 day 12에 대한 코드를 리팩터링했습니다. 함께 Map.withDefaultValue를 사용하는 방법이있다 : 스칼라에서 단안 문자로 보일러 플레이트를 줄이는 방법

이 코드를 개선 할 수 있는가 :

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) 
    } 

하나 개 더 질문의 수정을 분리, 시도이다 단안경?

전체 코드

은 여기에 있습니다 : https://gist.github.com/YannMoisan/b8ba25afc041d88706545527d9ec1988

+1

내가 대신 index''사용합니다 : 그래서 대신 foldLeft의 우리는 포인터 다음 명령을 추출하는 몇 가지 재귀 함수가 필요합니다 map의 값을 수정하고자 할 때'at '를 사용한다. (State.mem composeLens at (r)). 수정 (_. map (_ + 1)) ' –

답변

-1
이 두 필드의 처리를 분리하기 때문에 당신은 두 번째 방법을 사용할 수 있습니다

. 그러나 함수는 순서대로 해석해서는 안되며 (andThen) PartialFunctionorElse으로 결합해야합니다. 합니다 (얀 Moisan 주석 후)

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

실행이 유저의 프로그램의 무한 루프의 경우에 종료 할 수있다.

@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 composeOptional index (r)). jump (jnz) 명령으로 인해 순서대로 실행됩니다. –

+0

다음은 두 가지 측면입니다. 하나는 모듈성입니다 - 다양한 종류의 명령어를 개별적으로 처리합니다. 그리고 이것은'PartialFunction'에 의해 달성됩니다. 다른 측면은 일반 명령어 (실행 및 포인터 진행)에 대한 두 단계의 순차적 실행입니다. 두 aspect는'processInstruction3'에서 적절하게 처리됩니다. 'processInstruction2' ('ptr와'mem')'Jnz'의 경우 두 번째 패턴 매칭 블록에 의해 처리 될 것입니다. (다행스럽게도 다른 비슷한 명령어가 없으므로 디폴트 케이스를 통과 할 것입니다.) –