Suppose I have a few functions:
val f1: Int => String
val f2: (Int, Int) => String
val f3: (Int, Int, Int) => String
def fromList1(f: Int => String): List[Int] => Option[String] =
_ match {case x::_ => Some(f(x)); case _ => None}
def fromList2(f: (Int, Int) => String): List[Int] => Option[String] =
_ match {case x::y::_ => Some(f(x, y)); case _ => None}
Now I would like to write one generic fromList
to work as follows:
val g1: List[Int] => String = fromList(f1) // as fromList1(f1)
val g2: List[Int] => String = fromList(f2) // as fromList2(f2)
Can I do that with shapeless
?
This may help:
import shapeless._
import syntax.std.traversable._
import shapeless.ops.traversable._
import syntax.std.function._
import ops.function._
def fromList[F, L <: HList, R](f: F)
(implicit fp: FnToProduct.Aux[F, L => R], tr: FromTraversable[L]) =
(p: List[Int]) => p.toHList[L] map f.toProduct
f.toProduct
transforms regular function to function that takes HList
as parameter - it requires FnToProduct
implicit and actually just call it. FnToProduct.Aux
is constructor (generated by macro) that creates FnToProduct
from dunction F
, hlist type HList
and result type R
. All of them are inferred from f
parameter you passed.
Last one, toHList
creates Some(HList)
from regular List
if it's possible, otherwise - None
. It uses FromTraversable[L]
implicit to do that, where L
is already inferred from f
. Shapeless2 is smart enough to recognize HList
from Tuple
(as there probably is implicit conversion).
Example:
scala> val f1: Int => String = _ => "a"
f1: Int => String = <function1>
scala> val f2: (Int, Int) => String = (_, _) => "a"
f2: (Int, Int) => String = <function2>
scala> val g1 = fromList(f1)
g1: List[Int] => Option[String] = <function1>
scala> g1(List(1))
res6: Option[String] = Some(a)
scala> val g2 = fromList(f2)
g2: List[Int] => Option[String] = <function1>
scala> g2(List(1, 2))
res7: Option[String] = Some(a)
scala> g2(List(1))
res8: Option[String] = None
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With