我想在Scala中实现一个库。 我刚刚开始,我已经无法以模块化和可扩展的方式设计它。
我需要一些帮助!例如,我已经定义了一个树ADT
sealed trait Tree[+A,+B,+C]
case object EmptyTree extends Tree[Nothing, Nothing, Nothing]
case class Leaf[A,B,C](value: C) extends Tree[A,B,C]
case class Branch_A1[A,B,C](op: B, left: Tree[A,B,C]) extends Tree[A,B,C]
case class Branch_A2[A,B,C](op: A, left: Tree[A,B,C], right: Tree[A,B,C]) extends Tree[A,B,C]
Branch_A#表示具有#参数的函数。你可以看到它的发展方向。
为什么A,B和C?因为Leafs将是例如Double,我有两种类型的函数Double =>双和(双,双)=>双。当我增加分支的数量多样性时,我担心这会如何扩展。我想让这个非常灵活
我有两个问题,一个是技术问题,另一个是关于我的设计模式。
技术问题
当我尝试定义泛型方法来操作这样的结构时,我得到编译错误,这是我无法解决的。例如:
sealed trait Tree[+A,+B,+C] {
def evaluateTree[A,B,C] (t: Tree[A,B,C]): C = t match {
case Leaf(value) => value
case Branch_A1(op, left) => op(evaluateTree(left))
case Branch_A2(op, left, right) => op(evaluateTree(left),evaluateTree(right))
}
}
case object EmptyTree extends Tree[Nothing, Nothing, Nothing]
case class Leaf[A,B,C](value: C) extends Tree[A,B,C]
case class Branch_A1[A,B,C](op: B, left: Tree[A,B,C]) extends Tree[A,B,C]
case class Branch_A2[A,B,C](op: A, left: Tree[A,B,C], right: Tree[A,B,C]) extends Tree[A,B,C]
在op(evaluateTree(left))
我得到“应用程序不支持参数”。我不明白为什么。
设计问题
如果允许图书馆的用户表达更高的arity功能的域,则这将难以管理。我想,泛型类型的数量会爆炸。我怎样才能以更好的方式设计它?我想让这个可扩展。通用类型的使用是最合适的吗?还是应该换个方式?我读到有关抽象数据类型的替代方法
答案 0 :(得分:0)
致技术问题:编译器没有足够的有关A
或B
的信息,无法知道op(...)
是否可能/允许,或者如果被调用,它将返回正确的类型。
如果(使用更简单的例子)你写了case Leaf(value) => value-1
怎么办?除非已将C
定义/限制为某些已知具有匹配返回类型的-(x:Int)
方法的类型子集,否则编译器不会允许这样做。
答案 1 :(得分:0)
在第二天,我再次看到问题,这一切都有意义。只是我让仿制药比实际上复杂得多。
我之前曾说过,仿制药类型[A,B,C]可能意味着[(Double,Double)=> Double,Double =>双,双]。所以我只需要一个参数化类型:
sealed trait Tree[+A]
case object EmptyTree extends Tree[Nothing]
case class Leaf[A](value: A) extends Tree[A]
case class Branch_A1[A](op: A => A, left: Tree[A]) extends Tree[A]
case class Branch_A2[A](op: (A,A) => A, left: Tree[A], right: Tree[A]) extends Tree[A]