有企业和人。用户可以喜欢或发表关于企业的评论,但同样如此不能发生在一个人身上。当用户发布有关某项业务或喜欢它的内容时,该业务称为 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 的了解而言,我无法以令人满意的方式对这种特定的事态进行建模。现在我坚持认为这是不是 子类型,因为业务是 不是 A:
class Business extends
TargetingRelation[Post,Business] with
TargetingRelation[Like,Business]
事实上,
Business
是非常可取的。仍然完全不知道 Post
.这种关系实际上是在两者之外 Post
和 Business
.此外,我想上面的代码甚至无法编译,因为 Business
继承自 TargetingRelation
两次。见解是最受欢迎的。相关:Using a context bound in a class type parameter
最佳答案
您可以在 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”中搜索,你会发现很多 explanations of the details这是如何工作的,但基本上,您需要构造函数采用
TargetingRelation[TargetingType[_],TargetedType]
类型的隐式参数。然后在构造类( Post
或 Like
)时在范围内放置该类型的隐式。隐式作为 TargetedType
的“证据”有一个类型类的实例(并扮演在其他语言类型类实现中自动传递的方法的显式字典的角色)。事实上,scala 有一些合成糖可以帮助解决这个问题,称为 Context Bound .这会导致方法写为:
def a[A: B] = ???
翻译成
def a[A](implicit ev: B[A]) = ???
在您的特定示例中,上下文边界语法有点棘手,因为有多个类型参数,但可以作为 this SO question 完成。描述。
关于scala - 对两种类型之间的二元关系建模,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20438322/