2017-10-12 60 views
0

我想了解的無形的副產品,並有下面的例子中,不工作:找不到參數ENC隱含值:CsvEncoder [形狀]

import shapeless.{HList, ::, HNil} 
import shapeless.Generic 
import shapeless.{Coproduct, :+:, CNil, Inl, Inr} 

trait CsvEncoder[A] { 
    def encode(value: A): List[String] 
} 


sealed trait Shape 

final case class Rectangle(width: Double, height: Double) extends Shape 

final case class Circle(radius: Double) extends Shape 

object CsvEncoder { 

    def createEncoder[A](func: A => List[String]): CsvEncoder[A] = { 
    new CsvEncoder[A] { 
     override def encode(value: A): List[String] = func(value) 
    } 
    } 

    implicit val booleanEncoder: CsvEncoder[Boolean] = 
    createEncoder(value => if (value) List("yes") else List("no")) 

    implicit val intEncoder: CsvEncoder[Int] = 
    createEncoder(value => List(value.toString)) 

    implicit val stringEncoder: CsvEncoder[String] = 
    createEncoder(value => List(value)) 

    implicit val doubleEncoder: CsvEncoder[Double] = 
    createEncoder(value => List(value.toString)) 


    def apply[A](implicit enc: CsvEncoder[A]): CsvEncoder[A] = enc 

    implicit val cnilEncoder: CsvEncoder[CNil] = 
    createEncoder(cnil => throw new Exception("Inconceivable!")) 

    implicit def coproductEncoder[H, T <: Coproduct](
                implicit 
                hEncoder: CsvEncoder[H], 
                tEncoder: CsvEncoder[T] 
               ): CsvEncoder[H :+: T] = createEncoder { 
    case Inl(h) => hEncoder.encode(h) 
    case Inr(t) => tEncoder.encode(t) 
    } 

    def writeCsv[A](values: List[A])(implicit enc: CsvEncoder[A]): String = 
    values.map(value => enc.encode(value).mkString(",")).mkString("\n") 


} 

object Main { 


    def main(args: Array[String]) { 

    println("----------------------------------------------------------") 
    val shapes: List[Shape] = List(
     Rectangle(3.0, 4.0), 
     Circle(1.0) 
    ) 
    println(CsvEncoder.writeCsv(shapes)) 

    } 

} 

編譯器會抱怨:

Error:(162, 32) could not find implicit value for parameter enc: CsvEncoder[Shape] 
    println(CsvEncoder.writeCsv(shapes)) 
Error:(162, 32) not enough arguments for method writeCsv: (implicit enc: CsvEncoder[Shape])String. 
Unspecified value parameter enc. 
    println(CsvEncoder.writeCsv(shapes)) 

我是否已經爲Shape創建了CsvEncoder的實例?無形的人應該照顧它,或者?

回答

3

我推薦重新讀/ The Type Astronaut's Guide to Shapeless Book,它確實是一本很棒的書。看起來你發佈的代碼部分來自那裏。


的CSV編碼器示例使用Employee,並寫入CsvEncoder手動(第23頁):

implicit val iceCreamEncoder: CsvEncoder[IceCream] = 
    new CsvEncoder[IceCream] { 
    def encode(i: IceCream): List[String] = 
     List(
     i.name, 
     i.numCherries.toString, 
     if(i.inCone) "yes" else "no" 
    ) 
    } 

如果希望有手工編寫這一切,你」需要更多的樣板。


這是書中的描述3.2.1第27頁的周圍:

import shapeless.{HList, ::, HNil} 
implicit val hnilEncoder: CsvEncoder[HNil] = 
    createEncoder(hnil => Nil) 
implicit def hlistEncoder[H, T <: HList](
    implicit 
    hEncoder: CsvEncoder[H], 
    tEncoder: CsvEncoder[T] 
): CsvEncoder[H :: T] = 
    createEncoder { 
    case h :: t => 
     hEncoder.encode(h) ++ tEncoder.encode(t) 
    } 

我們有遞歸的情況下,hlistEncoder(返回CsvEncoder[H :: T]),這需要頭部和尾部,和基本大小寫編碼器hnilEncoder(返回CsvEncoder[HNil],因爲HList的末尾始終有一個HNil,就像每個其他鏈接列表一樣)。

但是,這足以對任何HList進行CSV編碼,但Rectangle不是HList!您需要使用Generic來回轉換。這是在書的3.2.2解釋,以前的部分之後(我轉換的代碼中使用Generic.Aux,這是無形的最重要的工具之一):

implicit def genericEncoder[A, R](
    implicit 
    gen: Generic.Aux[A, R], 
    enc: CsvEncoder[R] 
): CsvEncoder[A] = 
    createEncoder(a => enc.encode(gen.to(a))) 

gen.to轉換a(比方說Rectangle)到HList(so,Double :: Double :: HNil,並對其進行編碼。) 它還將Shape轉換爲Rectangle :+: Circle :+: CNil,因此您的Main按原樣運行:)。

相關問題