2014-10-29 50 views
6

另一個HList這個問題是從我剛纔的問題得出:What does HList#foldLeft() return?如何將HList變換與foldRight/foldLeft

我有這樣的場景:

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 
} 

此代碼,嘗試讀取的值幾列。

如果我打電話給readColumns(cursor, new Column[String] :: new Column[Int] :: HNil),我預計會得到String :: Int :: HNil

readColumns()方法編譯ok,但編譯器抱怨具體調用中的含義。

什麼是正確的工作方式?

更新1

這裏是2列調用時,我收到確切的錯誤信息:

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)] 

不知道如何幫助編譯器。 :-(

更新2

問:RightFolder.Aux[A, (HNil.type, Cursor, Int), readColumn.type, (B, Cursor, Int)]

回答

5

更新到地址編輯

下面是一個完整的工作示例:

爲什麼在 readColumns()隱含參數指定 HNil.type
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 
} 

然後:

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) 

這個編譯得很好,並且做了我對2.0.0和2.1.0-RC1的期望。

,我應該在我原來的答覆中提到,使用HNil.type一樣,是不理想的,它工作得很好,但明確地鍵入參數中的HNilfoldRight作爲HNil是一個更好的解決方案。請注意,由於HNil的靜態類型爲HNil.type,並且RightFolder在其第二個參數中不是協變的,所以您必須執行一個或另一個。

原來的答覆

有一個很小的錯誤在你readColumn定義 - 你返回Tuple4,但要返回一個Tuple3。下面應該工作:

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) 
     } 
    } 

它通常是一個好主意,提供了具有隱含的分辨率做無關的原因,任何隱式方法的顯式返回類型,但在這種情況下,顯式說明的返回類型也輪番上漲錯誤很快。

+0

謝謝,現在更好。爲什麼我必須爲'readColumns()'隱式參數指定'HNil.type'?它仍然不適用於具體的調用。:-( – 2014-10-29 14:42:26

+1

嗯,調用'readColumns'爲我設置了一個簡單的例子,我會看看,但可能不會有機會,直到今天下午晚些時候 – 2014-10-29 14:54:05

+0

我已經更新了問題確切的錯誤信息我正在收到,以便更好的診斷 – 2014-10-30 10:52:06