定义Scala特征的隐式视图 [英] Defining implicit view-bounds on Scala traits

查看:100
本文介绍了定义Scala特征的隐式视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个练习,在Scala中实现一个功能二叉搜索树,遵循我在Haskell中看到的类似模式。我有一个看起来像这样的结构:

$ $ p $ $ $ $ $ b def遍历:Seq [A]
...
}

案例类Branch [A](值:A,left:TreeNode [A],right:TreeNode [A])扩展TreeNode [A] {
def isLeaf:Boolean = false
def遍历:Seq [A] = ...
...
}

case class Leaf [A]()扩展TreeNode [A] {
def isLeaf:Boolean = true
def遍历:Seq [A] = Seq [A]()
...
}

我会 em> A 上放置一个类型约束,以便它只接受扩展 Ordered 的对象。看起来我需要在上的视图( [A<%Ordered [A]] > Branch 和 Leaf ,以及 TreeNode trait ..我不能在 TreeNode trait中执行此操作,因为不接受视图边界。



据我所知, code><% -style view-bounds是隐式定义的语法糖,所以应该有一种写法在 TreeNode trait中手动定义绑定。不过,我不确定我应该怎么做。我已经环顾了一下,但还没有远远超过某种隐含的需求来定义。



任何人都可以指向正确的方向吗?我完全从错误的角度来看待这个问题吗?

解决方案

问题是视图边界以及上下文边界都只是语法糖用于特定类型的隐式参数。当应用于泛型类的类型参数(与应用于泛型方法相反)时,这些含义被添加到类的构造函数中。
由于特征没有构造函数(或者说,只有一个无参数构造函数),所以无处传递这些隐式参数,因此上下文边界和视图边界在通用特征上是非法的。
最简单的解决方案是将 TreeNode 变成一个抽象类。:

  abstract class TreeNode [A<%Ordered [A]] 

由Ben James建议,使用与 Ordering 绑定的上下文通常优于用 ORdered 绑定的视图更普遍)。但是问题仍然存在:不适用于特征。



如果将 TreeNode 转换为类是不实际的(比如你需要在类型层次结构中的不同位置混合使用),你可以在 TreeNode 中定义一个抽象方法来提供隐式值(类型 Ordered [A] )并让所有扩展它的类定义它。这不幸的是更详细和明确,但你不能在这种情况下做得更好:

  trait TreeNode [A] {
implicit protected def toOrdered:A => Ordered [A]](value:A,left:TreeNode [A],right:TreeNode [A])extends TreeNode [A]
}

case class Branch [A& [A] {
protected def toOrdered =隐式[A =>有序[A]]
}

案例类叶[A <%Ordered [A]]()扩展TreeNode [A] {
保护def toOrdered =隐式[A = >已订购[A]]
}


I'm doing an exercise to implement a functional binary-search-tree in Scala, following a similar pattern that I've seen used in Haskell. I have a structure that looks something like this:

trait TreeNode[A] {
    def isLeaf: Boolean
    def traverse: Seq[A]
    ...
}

case class Branch[A](value: A, left: TreeNode[A], right: TreeNode[A]) extends TreeNode[A] { 
   def isLeaf: Boolean = false
   def traverse: Seq[A] = ...
   ... 
}

case class Leaf[A]() extends TreeNode[A] { 
    def isLeaf: Boolean = true
    def traverse: Seq[A] = Seq[A]()
    ... 
}

I'd like to put a type constraint on A so that it will only accept objects that extend Ordered. It looks like I need to define a view bound on A ([A <% Ordered[A]]) on Branch and Leaf, as well as the TreeNode trait.. I can't do this on the TreeNode trait, however, because view bounds aren't accepted.

As I understand, <%-style view-bounds are syntactic sugar for an implicit definition, so there should be a way to write to define the bound manually within the TreeNode trait. I'm not sure how I'm supposed to do this, though. I've looked around a bit, but haven't gotten much further than that some sort of implicit needs to be defined.

Can anybody point me in the right direction? Am I approaching this from the wrong angle entirely?

解决方案

The problem is that view bounds as well as context bounds are just syntactic sugar for specific types of implicit parameters. When applied to a type parameter of a generic class (as opposed to when applied to a generic method), these implicits are added to the constructor of the class. Because traits have no constructor (or rather, only have a single parameterless constructor), there is nowhere to pass these implicit parameters and thus context bounds and view bounds are illegal on generic traits. The simplest solution would be to turn TreeNode into an abstract class.:

abstract class TreeNode[A <% Ordered[A]]

Note that as advised by Ben James, using a context bound with an Ordering is usually better than a view bound with an ORdered (it is more genral). However the problem is still the same: won't work on a trait.

If turning TreeNode into a class is not practical (say you need to mix it at various places in the type hierarchy), you can define an abstract method in TreeNode that will provide the implicit value (of type Ordered[A]) and have all the classes that extend it define it. This unfortunately more verbose and explicit, but you can't do much better in this case:

trait TreeNode[A] {
  implicit protected def toOrdered: A => Ordered[A]
}

case class Branch[A<%Ordered[A]](value: A, left: TreeNode[A], right: TreeNode[A]) extends TreeNode[A] { 
   protected def toOrdered = implicitly[A => Ordered[A]]
}

case class Leaf[A<%Ordered[A]]() extends TreeNode[A] { 
    protected def toOrdered = implicitly[A => Ordered[A]]
}

这篇关于定义Scala特征的隐式视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆