Reputation: 1105
I need to write a function that will receive a function that will transform a List[T]
into a T
. For example, summing the elements of the list.
My first try was to use shapeless polymorphic functions as:
object sumPoly extends (List ~> Option) = {
def apply[T: Numeric](list: List[T]): Option = Some(list.sum)
}
but I get an error because shapeless expect the function to be def apply[T](...)
The function that receives the function above would look like:
def test(list: List[Any], f: (List ~> Option)) = {
val intTypeCase = TypeCase[List[Int]]
val doubleTypeCase = TypeCase[List[Double]]
val longTypeCase = TypeCase[List[Long]]
list match {
intTypeCase(l) => f(l)
doubleTypeCase(l) => f(l)
longTypeCase(l) => f(l)
// more type matchings here
}
...
}
Is there a way to achieve what I want to do?
After some searches I found that it is possible to do the following:
object sumPoly extends Poly1 {
implicit def caseListInt = at[List[Int]](x => x.sum)
implicit def caseListDouble = at[List[Double]](x => x.sum)
// more type matchings here
}
and calling sumPoly(List(1, 1, 1))
correctly returns 3
. But if I define the test
function as:
def test(list: List[Any], f: Poly1) = {
val intTypeCase = TypeCase[List[Int]]
val doubleTypeCase = TypeCase[List[Double]]
val longTypeCase = TypeCase[List[Long]]
list match {
intTypeCase(l) => f(l)
doubleTypeCase(l) => f(l)
longTypeCase(l) => f(l)
// more type matchings here
}
...
}
and pass the sumPoly
function, I get the errors like this for each type I defined in the test
function: could not find implicit value for parameter cse: shapeless.poly.Case[f.type,shapeless.::[List[Int],shapeless.HNil]]
Any ideas?
Upvotes: 1
Views: 324
Reputation: 1105
By looking at shapeless' code I found I can do the following:
object sumPoly extends Poly1 {
implicit def caseList[T: Numeric] = at[List[T]] { x => x.sum }
}
and then the function which will receive the Poly1
must have the following definition:
def test(list: List[Any], f: Poly1)
(implicit li : f.Case[List[Int]],
ld : f.Case[List[Double]],
ll : f.Case[List[Long]])= {
val intTypeCase = TypeCase[List[Int]]
val doubleTypeCase = TypeCase[List[Double]]
val longTypeCase = TypeCase[List[Long]]
list match {
intTypeCase(l) => f(l)
doubleTypeCase(l) => f(l)
longTypeCase(l) => f(l)
// more type matchings here
}
...
}
this way, I can create different Poly1
functions like sum
, prod
, min
, max
that convert List[T]
into a T
where T
is numeric.
The design might seem contrived, but I am interop-ing with Java. More specifically, with Hadoop libraries written in Java.
Upvotes: 0