Modeling a binary relationship between two types

蓝咒 提交于 2019-12-04 09:26:31
kong

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!