4

有企业和人。用户可以喜欢或发表关于企业的评论,但同样不能发生在一个人身上。当用户发布有关某项业务或喜欢它的内容时,该业务称为该target喜欢或帖子的:

trait TargetingRelation[TargetingType[_],TargetedType]

class Business

class Person

class Post[Target | TargetingRelation[Business,Post] ] {
  def target:Target
}

class Like[Target | TargetingRelation[Business,Like] ] {
  def target:Target
}

在这里,我发明了一个T | P[T]表示类型参数的符号T,以便它满足某些属性P[T](或者T :|: P[T]如果它具有更多的类型吸引力)。我希望在代码中的其他地方声明如下:

object canPostAboutBusiness extends TargetingRelation[Post,Business] 
object canLikeBusiness      extends TargetingRelation[Like,Business]

这些对象实际上是证据,类似于 Haskell 类型类。所以这将输入检查:

val p = new Post[Business]
val l = new Like[Business]

不是这个:

val p = new Post[Person]
val l = new Like[Person]

就我对 Scala 的了解而言,我无法以令人满意的方式对这种特定的事态进行建模。现在我坚持认为这不是子类型,因为 Business不是

class Business extends 
  TargetingRelation[Post,Business] with 
  TargetingRelation[Like,Business]

事实上,Business完全不了解Post. 这种关系实际上在Post和之外Business。此外,我想上面的代码甚至不会编译开始,因为它是从两次Business继承的。TargetingRelation见解是最受欢迎的。

相关:使用绑定在类类型参数中的上下文

4

1 回答 1

6

您可以在 scala 中使用类似于使用隐式的类型类的东西来执行此操作。例如:

import scala.language.higherKinds

trait TargetingRelation[A[_], B]

class Business
class Person

// Using explicitly declared implicit parameter:
class Post[T](implicit ev: TargetingRelation[Post, T])

// Using a "context bound". The syntax is a little hairy and uses
// a type lambda because TargetingRelation takes multiple type params
class Like[T : ({type S[x] = TargetingRelation[Like, x]})#S]

implicit object canPostAboutBusiness extends TargetingRelation[Post,Business]
implicit object canLikeBusiness      extends TargetingRelation[Like,Business]

然后你可以实例化类Business

scala> val p = new Post[Business]
p: Post[Business] = Post@374c991a

scala> val l = new Like[Business]
l: Like[Business] = Like@1fd348f8

但不与Person

scala> val p1 = new Post[Person]
<console>:15: error: could not find implicit value for parameter ev: TargetingRelation[Post,Person]
       val p1 = new Post[Person]
                ^

scala> val p2 = new Like[Person]
<console>:15: error: could not find implicit value for evidence parameter of type TargetingRelation[Post,Person]
       val p2 = new Like[Person]
                ^

如果你从“scala typeclasses”中搜索,你会发现很多关于它是如何工作的细节的解释,但基本上,你需要构造函数获取该类型的隐式参数,TargetingRelation[TargetingType[_],TargetedType]然后在范围内放置该类型的隐式参数构建你的类(PostLike)。隐式作为TargetedType具有类型类实例的“证据”(并扮演在其他语言类型类实现中自动传递的方法的显式字典的作用)。

事实上,scala 有一些语法糖可以帮助解决这个问题,称为Context Bound。这导致方法编写为:

def a[A: B] = ???

被翻译成

def a[A](implicit ev: B[A]) = ???

在您的特定示例中,上下文边界语法有点棘手,因为有多个类型参数,但可以按照这个 SO question的描述来完成。

于 2013-12-07T07:55:33.633 回答