2017-02-23 46 views
1

美好的一天,斯卡拉 - 使用参数指定函数的类型

我在大学有一个任务,我们需要为某种语言编写解析器。该语言的核心功能之一是为NumC和StringC(核心语言中的数字和字符串表示)编写了一个equals方法。这两种方法都会评估为BoolV(x),其中x为真或假(BoolV代表此语言中的布尔值)。

我用下面的代码成功地完成了这个工作(请注意,所有的输入都是ExprC,它是所有Core功能的超类,并且interp函数负责将ExprC转换为Values):

def str_cmp(l: ExprC, r: ExprC): BoolV = (interp(l), interp(r)) match { 
    case (StringV(x), StringV(y)) => BoolV(x == y) 
    case _ => throw NotStringException("Atleast one argument value does not evaluate to a String.") 
} 

def num_cmp(l: ExprC, r: ExprC): BoolV = (interp(l), interp(r)) match { 
    case (NumV(x), NumV(y)) => BoolV(x == y) 
    case _ => throw NotNumberException("Atleast one argument value does not evaluate to a number.") 
} 

正如您可能会注意到的,这些功能非常相似;只有被检查的类型才会改变(以及异常,但这些都是来自同一异常的子类)。

现在我想知道是否有一些工具,它会产生类似以下功能:

def compare[A](l: ExprC, r: ExprC): BoolV = (interp(l), interp(r)) match { 
case (A(x), A(y)) => BoolV(x == y) 
case _ => throw NotValidArgument("Atleast one argument value does not evaluate to " + A + ".") 

这意味着,人们可以以某种方式另一个指定类型,无论lr的插补必须导致为了使比较方法评估而不是抛出错误。我知道上面的代码没有任何正确的语法,但我想知道是否有方法在Scala中编写此功能。

回答

1

使用ClassTag可能是你在找什么来解决问题:

import reflect.ClassTag 

def compare[T : ClassTag](l: ExprC, r: ExprC): BoolV = { 
    val ct = implicitly[ClassTag[T]] 
    (interp(l), interp(r)) match { 
     case (ct(x), ct(y)) => BoolV(x == y) 
     case _ => throw new Exception("At least one argument value does not evaluate to " + ct + ".") 
    } 
} 
+0

对不起,我迟到的反应。这些被称为的方式有两种不同的方式;当比较两个表达式(这些表达式应该计算为字符串)时调用字符串比较,并且数字比较也是如此。我想传递泛型类型的原因是因为我不希望字符串比较用两个表达式来计算数字。在您创建的代码中,情况并非如此。 –

+0

好吧,但我真的不明白为什么字符串会评估为数字.. – meucaa

+0

这是一个有点抽象的结构,但是你有一个Core语言符号'EqStringC(l:ExprC,r:ExprC)',它有两个ExprC作为属性。这些Expr可以在解释这些之后评估为布尔值,数字或字符串。因此,我想确保EqStringC只有在ExprC评估为StringVs时才能成功。 –