Dynamically parameterize Poly1 function in shapeless

I have this situation (reduced to the main parts)

class Foo[L <: HList](columns: L) { class toRecord(row: Row) extends Poly1 { implicit def caseColumn[T] = at[Column[T]] { /* map to a record field */ } } def asRecord = { val resultSet: Stream[Row] = // computation to get result set resultSet.map { row => val m = new toRecord(row) // this can't work columns.map(m) } } } 

This does not work, since map wants to have a stable identifier, but m does not. So I need as many Poly1 singleton objects as I have rows in the result set.

This is the same issue discussed here: https://groups.google.com/forum/#!topic/shapeless-dev/P5DXRgnzqkY , but I can not find a way to make this work.

In a related discussion, Miles Sabin suggested Poly2 with Poly2 instead of map with Poly1 , but I cannot figure out how to use this sentence in my case.

+6
source share
1 answer

So, I managed to use Poly2 with foldRight to model a parametric map.

Here is an example to get an idea

 object toRecord extends Poly2 { implicit def caseColumn[A, B] = at[Column[A], (Row, B)] { case (col, (row, acc)) => val field = doMyThingy(row, col) // "map" `col` to a recordField using `row` as parameter (row, field :: acc) } } def asRecord[L <: HList, O <: HList]( implicit folder: RightFolder[L, (Row, HNil.type), toRecord.type, (Row, O)] ): Stream[O] = { val resultSet: Stream[Row] = // computation to get result set resultSet.map { row => columns.foldRight((row, HNil))(toRecord)._2 } } 

Thus, the “trick” here is to pass the parameter as the initial value of the bend and transfer it during the calculation.

Inside the calculation, we apply a transformation for each element, using row as a parameter (our “parametric mapping”), and then just add it to the battery.

When everything is ready, we get a tuple containing row and displayed HList : we can just discard the old one ( ._2 ), and we are good to go.

+5
source

Source: https://habr.com/ru/post/973770/


All Articles