Programming in Sala 책으로 스칼라 스터디하면서 정리했던 내용이다. 지금은 3판 번역본도 나왔지만, 약간 앞서서 스터디를 시작해서 2판으로 진행했다.

18장

변경 가능한 상태

  • 순수 함수형은 변경 가능한 상태가 없음.
  • var 이 있더라도 캐시 등의 용도라면 순수 함수형일 수 있음.
  • var 이 없더라도 변경 가능한 상태를 가진 다른 객체에게 호출을 위임하면서 변경 가능한 상태를 가질 수 있음.

재할당 가능한 변수

  • 비공개가 아닌 모든 var 멤버에 게터/세터 메소드를 자동으로 정의함.
  • var x의 게터는 x, 세터는 x_=
  • 게터와 세터는 원래 var과 같은 가시성을 가지고, 필드는 private[this]가 붙음
class Time {
  var hour = 12
  var minute = 0
}

// 실제 자동 확장
class Time {
  private[this] hour = 12
  private[this] minute = 0

  def hour: Int = h
  def hour_= (x: Int) { h = x }

  def minute: Int = m
  def minute_= (x: Int) { m = x }
}

// 직접 정의
class Time {
  private[this] hour = 12
  private[this] minute = 0

  def hour: Int = h
  def hour_= (x: Int) {
    require(0 <= x && x < 24)
  }

  def minute: Int = m
  def minute_= (x: Int) {
    require(0 <= x && x < 60)
    m = x
  }
}
  • 연관된 필드 없이 게터/세터 정의
class Thermometer {
  var celsius: Float = _    // 초기화 값.

  def fahrenheit = celsius * 9 / 5 + 32
  def fahrenheit_= (f: Float) {
    celsius = (f - 32) * 5 / 9
  }

  override def toString = fahrenheit +"F/"+ celsius +"C"
}
  • 필드 초기화 값
    • 수 타입 : 0
    • 불리언 타입 : false
    • 레퍼런스 타입 : null
  • = _ 초기화를 생략하면 추상 변수(20장)를 선언함

예 : 이산 이벤트 시뮬레이션

package org.stairwaybook.simulation

abstract class Simulation {
  type Action = () => Unit
  case class WorkItem(time: Int, action: Action)
  
  private var curtime = 0
  def currentTime: Int = curtime
  private var agenda: List[WorkItem] = List()
  
  private def insert(ag: List[WorkItem], item: WorkItem): List[WorkItem] = {
    if (ag.isEmpty || item.time < ag.head.time) item :: ag
    else ag.head :: insert(ag.tail, item)
  }

  def afterDelay(delay: Int)(block: => Unit) {
    val item = WorkItem(currentTime + delay, () => block)
    agenda = insert(agenda, item)
  }

  private def next() {
    (agenda: @unchecked) match {
      case item :: rest =>
        agenda = rest
        curtime = item.time
        item.action()
    }
  }

  def run() {
    afterDelay(0) {
      println("*** simulation started, time = "+ currentTime +" ***")
    }
    while (!agenda.isEmpty) next()
  }
}

abstract class BasicCircuitSimulation extends Simulation {
  def InverterDelay: Int
  def AndGateDelay: Int
  def OrGateDelay: Int

  class Wire {
    private var sigVal = false
    private var actions: List[Action] = List()
    
    def getSignal = sigVal
    
    def setSignal(s: Boolean) {
      if (s != sigVal) {
        sigVal = s
        actions foreach (_ ())
      }
    }
    
    def addAction(a: Action) {
      actions = a :: actions
      a()
    }
  }

  def inverter(input: Wire, output: Wire) {
    def invertAction() {
      val inputSig = input.getSignal
      afterDelay(InverterDelay) {
        output setSignal !inputSig
      }
    }
    input addAction invertAction
  }

  def andGate(a1: Wire, a2: Wire, output: Wire) {
    def andAction() = {
      val a1Sig = a1.getSignal
      val a2Sig = a2.getSignal
      afterDelay(AndGateDelay) {
        output setSignal (a1Sig & a2Sig)
      }
    }
    a1 addAction andAction
    a2 addAction andAction
  }

  def orGate(o1: Wire, o2: Wire, output: Wire) {
    def orAction() {
      val o1Sig = o1.getSignal
      val o2Sig = o2.getSignal
      afterDelay(OrGateDelay) {
        output setSignal (o1Sig | o2Sig)
      }
    }
    o1 addAction orAction
    o2 addAction orAction
  }

  def probe(name: String, wire: Wire) {
    def probeAction() {
      println(name +" "+ currentTime +" new-value = "+ wire.getSignal)
    }
    wire addAction probeAction
  }
}

abstract class CircuitSimulation extends BasicCircuitSimulation {
  def halfAdder(a: Wire, b: Wire, s: Wire, c: Wire) {
    val d, e = new Wire
    orGate(a, b, d)
    andGate(a, b, c)
    inverter(c, e)
    andGate(d, e, s)
  }

  def fullAdder(a: Wire, b: Wire, cin: Wire, sum: Wire, cout: Wire) {
    val s, c1, c2 = new Wire
    halfAdder(a, cin, s, c1)
    halfAdder(b, s, sum, c2)
    orGate(c1, c2, cout)
  }
}
import org.stairwaybook.simulation._

object MySimulation extends CircuitSimulation {
  def InverterDelay = 1
  def AndGateDelay = 3
  def OrGateDelay = 5
}

import MySimulation._

val input1, input2, sum, carry = new Wire
probe("sum", sum)
probe("carry", carry)
halfAdder(input1, input2, sum, carry)
input1 setSignal true
run()
input2 setSignal true
run()


+ Recent posts