#scala #pattern-matching #semantics
#scala #сопоставление с образцом #семантика
Вопрос:
Здесь я написал код из двух правил, связанных с обработкой сред в Scala. В коде все работает отлично, однако я не слишком уверен в определениях, которые я написал, чтобы объяснить, что происходит за капотом. Я не уверен, может ли кто-нибудь проверить мои правила на правильность? Я не уверен в переводе семантических правил. Для второго правила я понимаю, что недопустимая переменная приведет к оценке ошибки. Мне не ясно, в каком правиле 1 должно быть определено.
sealed trait Environment
sealed trait Value
case object EmptyEnv extends Environment
case class Extend(x: String, v: Value, sigma: Environment) extends Environment
case class ExtendRec(f: String, x: String, e: Expr, sigma: Environment ) extends Environment
case class ExtendMutualRec2(f1: String, x1: String, e1: Expr, f2: String, x2: String, e2: Expr, sigma: Environment) extends Environment
/* -- We need to redefine values to accomodate the new representation of environments --*/
case class NumValue(d: Double) extends Value
case class BoolValue(b: Boolean) extends Value
case class Closure(x: String, e: Expr, pi: Environment) extends Value
case object ErrorValue extends Value
/*2. Operators on values */
def valueToNumber(v: Value): Double = v match {
case NumValue(d) => d
case _ => throw new IllegalArgumentException(s"Error: Asking me to convert Value: $v to a number")
}
def valueToBoolean(v: Value): Boolean = v match {
case BoolValue(b) => b
case _ => throw new IllegalArgumentException(s"Error: Asking me to convert Value: $v to a boolean")
}
def valueToClosure(v: Value): Closure = v match {
case Closure(x, e, pi) => Closure(x, e, pi)
case _ => throw new IllegalArgumentException(s"Error: Asking me to convert Value: $v to a closure")
}
/*-- Operations on environments --*/
def lookupEnv(sigma: Environment, x: String): Value = sigma match {
case EmptyEnv => throw new IllegalArgumentException(s"Error could not find string $x in environment")
case Extend(y, v, _) if y == x => v
case Extend(_, _, pi) => lookupEnv(pi, x)
case ExtendRec(f, y, e, pi) => if (x == f)
Closure(y, e, sigma)
else
lookupEnv(pi, x)
case ExtendMutualRec2(f1, x1, e1, f2, x2, e2, pi ) =>
{
if (x == f1)
Closure(x1, e1, sigma)
else if (x == f2)
Closure(x2, e2, sigma)
else
lookupEnv(pi, x)
}
}
case class Seq(e1: Expr, e2: Expr) extends Expr
....
....
case Seq(e1, e2) => {
val (v1, store1) = evalExpr(e1, env, store)
val (v2, store2) = evalExpr(e2, env, store1)
(v2, store2)
}
Комментарии:
1. Вашему вопросу не хватает некоторого контекста. Вероятно, перед взаимной рекурсией вы выполняли обычную рекурсию и нерекурсивную
let
.2. @DmytroMitin заранее извиняется. Я не хотел перегружать контент, полагая, что то, чего мне не хватает, очевидно. Это правильно. Пусть было предыдущим
3. Вы не указали
Expr
иерархию. Что такое подписьevalExpr
? Вы могли бы попробовать написать тестовую программу с взаимной рекурсией на вашем языке (напримерisOdd: Num -> Bool
,isEven: Num -> Bool
) и посмотреть, правильно ли она оценена.4. На первом скриншоте
eval
есть два параметра (выражение и среда), на втором — три параметра.5. Вы нашли ответы на свои вопросы?
Ответ №1:
Что касается правила 1, кажется, вам следует добавить еще один случай к вашему оценщику
def evalExpr(e: Expr, env: Environment, store: ???): (Value, ???) = e match {
//...
case Seq(e1, e2) =>
val (v1, store1) = evalExpr(e1, env, store)
val (v2, store2) = evalExpr(e2, env, store1) // what if v1 = error?
(v2, store2)
case LetRec2(f1, x1, e1, f2, x2, e2, env) =>
evalExpr(e, ExtendMutualRec2(f1, x1, e1, f2, x2, e2, env), store /*???*/)
}