Reputation: 18177
I have the following code that I would like to abstract for additional types:
val users = Set[User](new User(1, "tyler"), new User(2, "phil"), new User(3, "quan"))
val groups = Set[Group](new Group(1, 10, 1), new Group(2, 20, 3))
def myFind(user: User)(implicit g: Group): Boolean = {
user.id == g.adminID
}
val combined = groups.map(implicit g => {
val admin = users.find(myFind)
// Do something with relation
g.toString + " " + admin.toString
})
println(combined)
What I would like to do is turn this into a function. What I have so far is:
def myFunc[A, B](s1: Set[A], s2: Set[B], f: (B) => Boolean): Set[String] = {
s1.map(implicit t1 => {
val rel = s2.find(f)
t1.toString + " " + rel.to
})
}
myFunc(users, groups, myFind)
There are two compilation errors:
Could not find implicit value for parameter g: Sets.Group
myFunc(users, groups, myFind)
^
And
Not enough arguments for method myFind: (implicit g: Sets.Group)Boolean.
Unspecified value parameter g.
myFunc(users, groups, myFind)
^
EDIT: Full code:
case class User(id: Int, name: String)
case class Group(id: Int, membersCount: Int, adminID: Int)
object Playground {
def main(args: Array[String]) {
val users = Set[User](new User(1, "tyler"), new User(2, "phil"), new User(3, "quan"))
val groups = Set[Group](new Group(1, 10, 1), new Group(2, 20, 3))
def myFind(user: User)(implicit g: Group): Boolean = {
user.id == g.adminID
}
val combined = groups.map(implicit g => {
val admin = users.find(myFind)
// Do something with relation
g.toString + " " + admin.toString
})
println(combined)
myJoin(users, groups, myFind)
}
def myJoin[A, B](s1: Set[A], s2: Set[B], f: (B) => Boolean): Set[String] = {
s1.map(implicit t1 => {
val rel = s2.find(f)
t1.toString + " " + rel.to
})
}
}
Upvotes: 1
Views: 67
Reputation: 14224
The problem is that in myFunc
at the point where you call s2.find(f)
there is no information that f
takes any implicit parameters. And you can't express this kind of information in the type signature of a function argument.
I believe, your best bet is to have myFunc
take a function from both A
and B
to Boolean
(either (A, B) => Boolean
or A => B => Boolean
).
For example:
def myFunc[A, B](s1: Set[A], s2: Set[B], f: A => B => Boolean): Set[String] =
s1.map { t1 =>
val rel = s2.find(f(t1))
t1.toString + " " + rel.to
}
Then for this definition of myFunc
, you can pass myFind
to it in one of those ways:
myFunc(users, groups, (u: User) => { implicit g: Group => myFind(u)})
Or
myFunc(users, groups, (u: User) => (g: Group) => myFind(u)(g))
Or define a function without implicit parameters and pass it directly:
def myFind2(user: User)(g: Group): Boolean = user.id == g.adminID
myFunc(users, groups, myFind2)
Or if you have a function from two arguments you can pass it to myFunc
using curried
method:
def myFind3(user: User, g: Group): Boolean = user.id == g.adminID
myFunc(users, groups, (myFind3 _).curried)
Upvotes: 2