-
재귀로 인해 추가된 코드 부분컴공지식/프로그래밍언어론 2024. 10. 27. 17:07
trait Expr
case class Num(n: Int) extends Expr
case class Add(lhs: Expr, rhs: Expr) extends Expr
case class Sub(lhs: Expr, rhs: Expr) extends Expr
case class Id(name: String) extends Expr
case class Fun(param: Id, body: Expr) extends Expr
case class App(funExpr: Expr, argExpr: Expr) extends Expr
case class If0(testExpr: Expr, thenExpr: Expr, elseExpr: Expr) extends Expr
case class Rec(fname: Id, namedExpr: Expr, fstCall: Expr) extends ExprIf0이랑 Rec이 새로 추가됐다.
case class If0(testExpr: Expr, thenExpr: Expr, elseExpr: Expr) extends Expr
은 testExpr이 0인지 검사해서, 참일 경우 thenExpr를 실행하고, 거짓일 경우 elseExpr를 실행한다.
case class Rec(fname: Id, namedExpr: Expr, fstCall: Expr) extends Expr
은 재귀 함수를 정의하는 표현이다.
다음은 interp 함수다.
// interp : Expr -> DefrdSub -> ExprValue
def interp(expr: Expr, ds: DefrdSub): ExprValue = expr match {
case Num(n) =>
NumV(n)
case Add(lhs, rhs) =>
numAdd(interp(lhs, ds), interp(rhs, ds))
case Sub(lhs, rhs) =>
numSub(interp(lhs, ds), interp(rhs, ds))
case Id(name) =>
lookup(name, ds)
case Fun(param, body) =>
ClosureV(param, body, ds)
case App(funExpr, argExpr) =>
val fVal = interp(funExpr, ds)
val aVal = interp(argExpr, ds)
fVal match {
case ClosureV(param, body, closureDs) =>
interp(body, ASub(param, aVal, closureDs))
case _ =>
throw new Exception("Expected a function")
}
case If0(testExpr, thenExpr, elseExpr) =>
if (numzero(interp(testExpr, ds)))
interp(thenExpr, ds)
else
interp(elseExpr, ds)
case Rec(fname, namedExpr, fstCall) =>
// 1. 더미 값을 사용해 valueHolder 초기화
var valueHolder = NumV(198) // 초기화용 임의 값
// 2. ARecSub를 사용해 새로운 DS 생성
val newDs = ARecSub(fname, valueHolder, ds)
// 3. namedExpr을 인터프리팅해서 함수 값으로 업데이트
valueHolder = interp(namedExpr, newDs)
newDs.valueBox = valueHolder // 박스에 실제 값 저장
// 4. 첫 번째 호출 실행
interp(fstCall, newDs)
}만약 valueHolder가 없다면 재귀 호출할 때 아직 함수 정의가 환경에 없어서 에러가 날 거다.
'컴공지식 > 프로그래밍언어론' 카테고리의 다른 글
JVM은 일종의 인터프리터 (0) 2024.11.03 Box 데이터 구조 (2) 2024.11.02 재귀 호출 비교 (1) 2024.10.27 에타 축약이란? (1) 2024.10.27 재귀 BNF (1) 2024.10.27