建模两种类型之间的二元关系

编程入门 行业动态 更新时间:2024-10-13 16:16:57
本文介绍了建模两种类型之间的二元关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 有企业和人员。用户可以喜欢或发表关于企业的评论,但是不能与某人发生相同。当用户发布关于企业或喜欢的东西时,该企业被称为目标的类似或发布:

< pre $ trait TargetingRelation [TargetingType [_],TargetedType] class商业 类Person class发布[目标| 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扩展了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:

类业务扩展 TargetingRelation [发布,业务]与 TargetingRelation [喜欢,商业]

事实上, Business 完全不知道 Post 。这种关系实际上在发布和商业之外。此外,我想上面的代码甚至不会编译,因为 Business 从 TargetingRelation >继承两次。洞察力是最受欢迎的。

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

解决方案

你可以在scala中用类似typeclass的东西来使用implicits。例如:

import scala.language.higherKinds trait TargetingRelation [A [_],B ] class Business class Person //使用显式声明的隐式参数: class Post [T](imp ev:TargetingRelation [Post, T]) //使用上下文绑定。语法有点毛,并且使用 //一个类型lambda,因为TargetingRelation需要多个类型参数 class Like [T:({type S [x] = TargetingRelation [Like,x]})#S ] 隐式对象canPostAboutBusiness extends TargetingRelation [Post,Business] 隐式对象canLikeBusiness extends TargetingRelation [Like,Business]

然后你可以通过 Business

阶> 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:找不到参数ev的隐式值:TargetingRelation [Post,Person] val p1 = new Post [Person] ^ scala> val p2 = new Like [Person] < console>:15:error:找不到类型为TargetingRelation [Post,Person]的证据参数的隐式值 val p2 = new Like [Person]

如果从scala typeclasses搜索,会发现很多详细解释,但基本上,您需要构造函数获取类型 TargetingRelation [TargetingType [_],TargetedType] 的隐式参数,然后放置在构造类时( Post 或 Like )),范围内隐含该类型。隐式作为证据用于证明 TargetedType 具有typeclass的一个实例(并且扮演显式字典中的方法的角色,这些方法在其他语言中自动传递类型类实现)。

事实上,scala有一些可以帮助解决这个问题的合成糖,叫做上下文绑定。这导致方法写成:

def a [A:B] = ???

被翻译为

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

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

There are businesses and people. Users can either like or post a comment about a business but the same can not happen with a person. When a user posts something about a business or likes it, that business is called the target of that like or post:

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 }

Here I'm inventing a T | P[T] notation meaning type parameter T such that it satisfies some property P[T] (or T :|: P[T] if it carries more type-appeal). Somewhere else in the code I want to have declarations like:

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

these objects are evidences actually, something like Haskell type-classes. So this would type check:

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

but not this one:

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

As far as my knowledge of Scala permits, I can't model this particular state of affairs in a satisfactory way. Now I insist that this is not sub-typing because Business is not a:

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

As a matter of fact it is very desirable that Business remains totally ignorant of the Post. The relationship is actually outside of both Post and Business. Besides, I suppose the above code would not even compile to begin with since Business is inheriting from TargetingRelation twice. Insights are most welcome.

related : Using a context bound in a class type parameter

解决方案

You can do this in scala with something that acts like a typeclass using implicits. For example:

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]

Then you can instantiate the classes with Business

scala> val p = new Post[Business] p: Post[Business] = Post@374c991a scala> val l = new Like[Business] l: Like[Business] = Like@1fd348f8

But not with 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] ^

If you search from "scala typeclasses", you'll find plenty of explanations of the details of how this works, but basically, you require the constructor to take an implicit parameter of the type TargetingRelation[TargetingType[_],TargetedType] and then place an implicit of that type in scope when constructing your class (Post or Like). The implicit serves as "evidence" that the TargetedType has an instance of the typeclass (and plays the role of the explicit dictionary of methods that get automatically passed around in other languages typeclass implementations).

In fact, scala has some synatic sugar to help with this, called the Context Bound. This causes methods written as:

def a[A: B] = ???

to be translated to

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

In your particular example, the contexts bounds syntax is a little tricky because there are multiple type parameters, but it can be done as this SO question describes.

更多推荐

建模两种类型之间的二元关系

本文发布于:2023-11-06 08:18:35,感谢您对本站的认可!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:建模   两种类型   关系

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!