Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I solve it with Shapeless?

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 ?

like image 919
Michael Avatar asked Aug 18 '15 11:08

Michael


1 Answers

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
like image 140
dk14 Avatar answered Oct 03 '22 05:10

dk14