我是Scala的新手,我很难定义,或者更有可能将我的代码从Ruby转换为评估描述为波兰语符号的计算。 f.e(+ 3 2)或( - 4(+ 3 2))
我成功地将字符串解析为ArrayBuffer(+,3,2)或ArrayBuffer( - ,4,ArrayBuffer(+,3 2))的形式
当我尝试定义一个递归eval函数时,问题实际上就开始了,它只是将ArrayBuffer作为参数并“返回”一个int(评估应用程序的结果)。
在基础案例中: 我想简单地检查第二个元素是否是一个instanceOf [Int]&&第3个元素是instanceOf [Int]然后一起评估它们(取决于符号运算符 - 第1个元素)并返回int。
但是如果任何元素是另一个ArrayBuffer,我只想将该元素重新分配给递归调用的eval函数的返回值。喜欢: 存储(2)= eval(存储(2)。(**这就是为什么我使用可变的ArrayBuffer **)
我得到的错误是: scala.collection.mutable.ArrayBuffer无法强制转换为java.lang.Integer
我当然不是在寻找任何复制和粘贴的答案,而是为了一些建议和观察。 建设性批评完全受到欢迎。
这是我仅用于添加 *
的测试代码def eval(Input: ArrayBuffer[Any]):Int = {
if(ArrayBuffer(2).isInstaceOf[ArrayBuffer[Any]]) {
ArrayBuffer(2) = eval(ArrayBuffer(2))
}
if(ArrayBuffer(3).isInstaceOf[ArrayBuffer[Any]]) {
ArrayBuffer(3) = eval(ArrayBuffer(3))
}
if(ArrayBuffer(2).isInstaceOf[Int] && ArrayBuffer(3).isInstanceOf[Int]) {
ArrayBuffer(2).asInstanceOf[Int] + ArrayBuffer(3).asInstanceOf[Int]
}
}
答案 0 :(得分:5)
您的代码存在一些问题:
ArrayBuffer(2)
表示“使用一个元素构建ArrayBuffer
:2
”。您的代码中没有任何地方引用您的参数Input
。您需要将ArrayBuffer(2)
的实例替换为Input(2)
才能生效。 ArrayBuffer
(以及Scala中的所有集合)都是0索引的,因此如果您想访问集合中的第二件事,您可以input(1)
。if
,那么编译器会抱怨,因为你的函数不会总是返回Int
;如果输入包含意外的内容,则最后if
将评估为false
,并且您没有else
落入。以下是您的代码的直接重写:解决问题:
def eval(input: ArrayBuffer[Any]):Int = {
if(input(1).isInstanceOf[ArrayBuffer[Any]])
input(1) = eval(input(1).asInstanceOf[ArrayBuffer[Any]])
if(input(2).isInstanceOf[ArrayBuffer[Any]])
input(2) = eval(input(2).asInstanceOf[ArrayBuffer[Any]])
input(1).asInstanceOf[Int] + input(2).asInstanceOf[Int]
}
(另请注意,变量名称,如input
,应该是小写的。)
也就是说,将输入中的条目替换为其评估的过程可能不是最佳路径,因为它会在评估过程中破坏输入。你应该编写一个带ArrayBuffer
的函数,只需简单地通过它来修改原文。
您需要eval
功能来检查特定情况。这是一个简单的实现演示:
def eval(e: Seq[Any]): Int =
e match {
case Seq("+", a: Int, b: Int) => a + b
case Seq("+", a: Int, b: Seq[Any]) => a + eval(b)
case Seq("+", a: Seq[Any], b: Int) => eval(a) + b
case Seq("+", a: Seq[Any], b: Seq[Any]) => eval(a) + eval(b)
}
所以你可以看到(+ arg1 arg2)
的简单情况,有4个案例。在每种情况下,如果参数是Int
,我们会在添加中直接使用它。如果参数本身是一个序列(like ArrayBuffer
),那么我们在添加之前递归计算。另请注意,Scala的case
语法允许与类型进行模式匹配,因此您可以跳过isInstanceOf
和asInstanceOf
内容。
现在肯定有你想要改进的样式改进(比如使用Either
代替Any
而不是硬编码"+"
),但这应该会让你正确的轨道。
以下是您将如何使用它:
eval(Seq("+", 3, 2))
res0: Int = 5
scala> eval(Seq("+", 4, Seq("+", 3, 2)))
res1: Int = 9
现在,如果您想真正利用Scala功能,可以使用Eval
提取器:
object Eval {
def unapply(e: Any): Option[Int] = {
e match {
case i: Int => Some(i)
case Seq("+", Eval(a), Eval(b)) => Some(a + b)
}
}
}
你会像这样使用它:
scala> val Eval(result) = 2
result: Int = 2
scala> val Eval(result) = ArrayBuffer("+", 2, 3)
result: Int = 5
scala> val Eval(result) = ArrayBuffer("+", 2, ArrayBuffer("+", 2, 3))
result: Int = 7
或者您可以将其包装在eval
函数中:
def eval(e: Any): Int = {
val Eval(result) = e
result
}
答案 1 :(得分:0)
以下是我从左到右的基于堆栈的评估:
def eval(expr: String): Either[Throwable, Int] = {
import java.lang.NumberFormatException
import scala.util.control.Exception._
def int(s: String) = catching(classOf[NumberFormatException]).opt(s.toInt)
val symbols = expr.replaceAll("""[^\d\+\-\*/ ]""", "").split(" ").toSeq
allCatch.either {
val results = symbols.foldRight(List.empty[Int]) {
(symbol, operands) => int(symbol) match {
case Some(op) => op :: operands
case None => val x :: y :: ops = operands
val result = symbol match {
case "+" => x + y
case "-" => x - y
case "*" => x * y
case "/" => x / y
}
result :: ops
}
}
results.head
}
}