2015-12-03 14 views
6

Mới đến không có hình dạng và tôi có câu hỏi về việc sử dụng các hàm đa hình cần một số phụ thuộc. Tôi về cơ bản có mã này và muốn kéo đối tượng somePoly ra khỏi phương pháp chạy:Kéo các chức năng đa hình không có phụ kiện có các phụ thuộc

import shapeless._ 
object SomeObject { 
    type SomeType = Int :+: String :+: (String, Int) :+: CNil 

    def run(someList: List[SomeType], someInt:Int, someWord:String) = { 

     object somePoly extends Poly1 { 
      implicit def doIt = at[Int](i => i + someInt + someWord.length) 
      implicit def doIt2 = at[String](i => i.length + someWord.length) 
      implicit def doIt3 = at[(String, Int)](i => i._1.length + someWord.length) 
     } 

     someList.map(_.map(somePoly)) 
    } 
} 

Một cách tôi nghĩ làm việc đó là như thế này, nhưng có vẻ như lộn xộn:

object TypeContainer { 
    type SomeType = Int :+: String :+: (String, Int) :+: CNil 
} 
case class SomePolyWrapper(someList: List[TypeContainer.SomeType], someInt:Int, someWord:String){ 
    object somePoly extends Poly1 { 
     implicit def doIt = at[Int](i => i + someInt + someWord.length) 
     implicit def doIt2 = at[String](i => i.length + someWord.length) 
     implicit def doIt3 = at[(String, Int)](i => i._1.length + someWord.length) 
    } 
} 
object SomeObject { 

    def run(someList: List[TypeContainer.SomeType], someInt:Int, someWord:String) = { 

     val somePolyWrapper = SomePolyWrapper(someList, someInt, someWord) 

     someList.map(_.map(somePolyWrapper.somePoly)) 
    } 
} 

Bất cứ ai có bất cứ khuyên bảo?

+0

Thảo luận gitter liên quan https://gitter.im/milessabin/shapeless?at=56608190d2a5a7813cd41422 – cvogt

Trả lời

4

Các giới hạn của hệ thống giải mã ngầm của Scala có nghĩa là định nghĩa Poly cần phải là định danh ổn định, điều này làm cho điều này trở nên đau đớn hơn. Như tôi đã đề cập trên Gitter, có một vài cách giải quyết mà tôi biết (có thể có những người khác).

Một cách tiếp cận sẽ là thực hiện Poly1 a PolyN, trong đó các đối số bổ sung dành cho các giá trị someIntsomeWord. Nếu bạn đã lập bản đồ qua số HList, thì bạn hãy sử dụng mapConstzip để làm cho đầu vào HList có hình dạng đúng. Tôi chưa bao giờ làm điều này cho một coproduct, nhưng một cái gì đó tương tự có khả năng làm việc.

Cách tiếp cận khác là sử dụng lớp loại tùy chỉnh. Trong trường hợp của bạn có thể trông giống như thế này:

import shapeless._ 

trait IntFolder[C <: Coproduct] { 
    def apply(i: Int, w: String)(c: C): Int 
} 

object IntFolder { 
    implicit val cnilIntFolder: IntFolder[CNil] = new IntFolder[CNil] { 
    def apply(i: Int, w: String)(c: CNil): Int = sys.error("Impossible") 
    } 

    def instance[H, T <: Coproduct](f: (H, Int, String) => Int)(implicit 
    tif: IntFolder[T] 
): IntFolder[H :+: T] = new IntFolder[H :+: T] { 
    def apply(i: Int, w: String)(c: H :+: T): Int = c match { 
     case Inl(h) => f(h, i, w) 
     case Inr(t) => tif(i, w)(t) 
    } 
    } 

    implicit def iif[T <: Coproduct: IntFolder]: IntFolder[Int :+: T] = 
    instance((h, i, w) => h + i + w.length) 

    implicit def sif[T <: Coproduct: IntFolder]: IntFolder[String :+: T] = 
    instance((h, i, w) => h.length + i + w.length) 

    implicit def pif[T <: Coproduct: IntFolder]: IntFolder[(String, Int) :+: T] = 
    instance((h, i, w) => h._1.length + i + w.length) 
} 

Và sau đó bạn có thể viết một phiên bản chung chung hơn của run của bạn:

def run[C <: Coproduct](
    someList: List[C], 
    someInt: Int, 
    someWord: String 
)(implicit cif: IntFolder[C]): List[Int] = someList.map(cif(someInt, someWord)) 

Và sử dụng nó như thế này:

scala> run(List(Coproduct[SomeType](1)), 10, "foo") 
res0: List[Int] = List(14) 

scala> run(List(Coproduct[SomeType](("bar", 1))), 10, "foo") 
res1: List[Int] = List(16) 

Tính đặc hiệu của hoạt động làm cho cách tiếp cận này trông hơi kỳ lạ, nhưng nếu tôi thực sự cần phải làm một cái gì đó như thế này cho các bản sao chép khác nhau, đây có lẽ là giải pháp mà tôi chọn.

+0

Thật tuyệt vời, cảm ơn! – azuras

Các vấn đề liên quan