gpt4 book ai didi

scala - 如何在 Scala 中将对象用作模块/仿函数?

转载 作者:行者123 更新时间:2023-12-04 15:27:50 25 4
gpt4 key购买 nike

我想将对象实例用作模块/仿函数,或多或少如下所示:

abstract class Lattice[E] extends Set[E] {
val minimum: E
val maximum: E
def meet(x: E, y: E): E
def join(x: E, y: E): E
def neg(x: E): E
}

class Calculus[E](val lat: Lattice[E]) {
abstract class Expr
case class Var(name: String) extends Expr {...}
case class Val(value: E) extends Expr {...}
case class Neg(e1: Expr) extends Expr {...}
case class Cnj(e1: Expr, e2: Expr) extends Expr {...}
case class Dsj(e1: Expr, e2: Expr) extends Expr {...}
}

这样我就可以为每个晶格创建一个不同的微积分实例(我将执行的操作需要晶格的最大值和最小值的信息)。我希望能够混合相同微积分的表达式,但不允许混合不同的表达式。到现在为止还挺好。我可以创建我的微积分实例,但问题是我不能在其他类中编写函数来操作它们。

例如,我正在尝试创建一个解析器来从文件中读取表达式并返回它们;我还尝试编写一个随机表达式生成器,以便在我的 ScalaCheck 测试中使用。事实证明,每次函数生成一个 Expr 对象时,我都不能在函数之外使用它。即使我创建了 Calculus 实例并将其作为参数传递给将生成 Expr 对象的函数,该函数的返回也不会被识别为与在函数外部创建的对象的类型相同。

也许我的英语不够清楚,让我尝试一个我想做的玩具示例(不是真正的 ScalaCheck 生成器,但足够接近)。
def genRndExpr[E](c: Calculus[E], level: Int): Calculus[E]#Expr = {
if (level > MAX_LEVEL) {
val select = util.Random.nextInt(2)
select match {
case 0 => genRndVar(c)
case 1 => genRndVal(c)
}
}
else {
val select = util.Random.nextInt(3)
select match {
case 0 => new c.Neg(genRndExpr(c, level+1))
case 1 => new c.Dsj(genRndExpr(c, level+1), genRndExpr(c, level+1))
case 2 => new c.Cnj(genRndExpr(c, level+1), genRndExpr(c, level+1))
}
}
}

现在,如果我尝试编译上面的代码,我会得到很多
 error: type mismatch;   found   : plg.mvfml.Calculus[E]#Expr   required: c.Expr          case 0 => new c.Neg(genRndExpr(c, level+1))  

And the same happens if I try to do something like:

val boolCalc = new Calculus(Bool)
val e1: boolCalc.Expr = genRndExpr(boolCalc)

请注意,生成器本身并不重要,但我需要在系统的其余部分上做很多类似的事情(即创建和操作微积分实例表达式)。

难道我做错了什么?
有可能做我想做的事吗?

非常需要和赞赏有关此问题的帮助。提前非常感谢。

在收到 Apocalisp 的回答并尝试之后。

非常感谢您的回答,但仍然存在一些问题。建议的解决方案是将函数的签名更改为:
def genRndExpr[E, C <: Calculus[E]](c: C, level: Int): C#Expr

我更改了所有相关函数的签名:getRndExpr、getRndVal 和 getRndVar。而且我在调用这些函数的任何地方都收到相同的错误消息,并收到以下错误消息:
error: inferred type arguments [Nothing,C] do not conform to method genRndVar's type parameter bounds [E,C <: plg.mvfml.Calculus[E]]        case 0 => genRndVar(c)

Since the compiler seemed to be unable to figure out the right types I changed all function call to be like below:

case 0 => new c.Neg(genRndExpr[E,C](c, level+1))

在此之后,在前 2 个函数调用(genRndVal 和 genRndVar)中没有编译错误,但在接下来的 3 个调用(对 genRndExpr 的递归调用)中,函数的返回用于构建一个新的 Expr 对象我得到了以下错误:

错误:类型不匹配;
发现:C#Expr
必需:c.Expr
案例 0 => 新 c.Neg(genRndExpr[E,C](c, level+1))

所以,再一次,我被困住了。任何帮助将不胜感激。

最佳答案

问题是 Scala 无法统一这两种类型 Calculus[E]#ExprCalculus[E]#Expr .

不过,这些对你来说都是一样的,对吧?好吧,考虑到您可以在某些类型上拥有两个不同的演算 E ,每个都有自己的Expr类型。而且您不想混合使用两者的表达方式。

您需要以返回类型相同的方式约束类型 Expr键入 Expr您的Calculus 的内在类型争论。你需要做的是:

def genRndExpr[E, C <: Calculus[E]](c: C, level: Int): C#Expr

关于scala - 如何在 Scala 中将对象用作模块/仿函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2611064/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com