How to convert an HList to another HList using foldRight / foldLeft

This question stems from my previous question: What does HList # foldLeft () return?

I have a scenario like this:

class Cursor { } trait Column[T] { def read(c: Cursor, index: Int): T } object Columns { object readColumn extends Poly2 { implicit def a[A, B <: HList] = at[Column[A], (B, Cursor, Int)] { case (col, (values, cursor, index)) β‡’ (col.read(cursor, index) :: values, cursor, index+1) } } def readColumns[A <: HList, B <: HList](c: Cursor, columns: A)(implicit l: RightFolder.Aux[A, (HNil.type, Cursor, Int), readColumn.type, (B, Cursor, Int)]): B = columnas.foldRight((HNil, c, 0))(readColumn)._1 } 

This code is trying to read the values ​​of multiple columns.

If I call readColumns(cursor, new Column[String] :: new Column[Int] :: HNil) , I expect to get String :: Int :: HNil .

The readColumns() method compiles fine, but the compiler complains about implicits in specific calls.

What is the correct way to work?

UPDATE 1 :

Here is the exact error message I get when calling with two columns:

 could not find implicit value for parameter l: shapeless.ops.hlist.RightFolder.Aux[shapeless.::[Column[String],shapeless.:: [Column[String],shapeless.HNil]],(shapeless.HNil.type, android.database.Cursor, Int),readColumn.type,(B, android.database.Cursor, Int)] 

I don’t know how to help the compiler. :-(

UPDATE 2 :

Question: why specify HNil.type in the implicit parameter readColumns() : RightFolder.Aux[A, (HNil.type, Cursor, Int), readColumn.type, (B, Cursor, Int)] ?

+6
source share
1 answer

Updating Address Settings

Here is a complete working example:

 class Cursor {} trait Column[T] { def read(c: Cursor, index: Int): T } import shapeless._, ops.hlist.RightFolder object Columns { object readColumn extends Poly2 { implicit def a[A, B <: HList]: Case.Aux[ Column[A], (B, Cursor, Int), (A :: B, Cursor, Int) ] = at[Column[A], (B, Cursor, Int)] { case (col, (values, cursor, index)) => (col.read(cursor, index) :: values, cursor, index + 1) } } def readColumns[A <: HList, B <: HList](c: Cursor, columns: A)(implicit l: RightFolder.Aux[ A, (HNil, Cursor, Int), readColumn.type, (B, Cursor, Int) ] ): B = columns.foldRight((HNil: HNil, c, 0))(readColumn)._1 } 

And then:

 val stringColumn = new Column[String] { def read(c: Cursor, index: Int) = "foo" } val intColumn = new Column[Int] { def read(c: Cursor, index: Int) = 10 } Columns.readColumns(new Cursor, stringColumn :: intColumn :: HNil) 

This compiles just fine and does what I expect from 2.0.0 and 2.1.0-RC1.

And I should have mentioned in my original answer that using HNil.type like this is not perfect - it works just fine, but explicitly dials HNil in the foldRight argument, since HNil better solution. Note that you must do one or the other, since the static type of HNil is equal to HNil.type , and RightFolder not covariant in the second argument.

Original answer

There is a very minor error in the definition of readColumn - you are returning Tuple4 , but you want to return Tuple3 . The following should work:

  object readColumn extends Poly2 { implicit def a[A, B <: HList]: Case.Aux[ Column[A], (B, Cursor, Int), (A :: B, Cursor, Int) ] = at[Column[A], (B, Cursor, Int)] { case (col, (values, cursor, index)) => (col.read(cursor, index) :: values, cursor, index+1) } } 

It is generally recommended that you specify an explicit return type for any implicit method for unrelated reasons related to implicit resolution, but in this case, an explicit description of the return type also quickly leads to an error.

+5
source

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