2016-09-20 1 views
7

मेरे पास एक एचएलिस्ट है जिसमें प्रत्येक कॉलम किसी तालिका के कॉलम का प्रतिनिधित्व करता है। एचएलिस्ट में प्रत्येक सूची एक ही लंबाई का है।सूची के एचएलआईस्ट के एनएच तत्व को चुनें और मूल्यों के एचएलिस्ट के रूप में उस मान को वापस करें

मैं एक ऐसा फ़ंक्शन लिखने में सक्षम होना चाहता हूं जो इस तालिका के अलग-अलग पंक्तियों को टुपल या मानों के एचएलिस्ट के रूप में चुनता है। आखिर में मैं इसे कुछ और समझदार (जैसे एक केस क्लास) में परिवर्तित कर दूंगा।

import shapeless.PolyDefns.~> 
import shapeless.{HList, HNil} 
val a = List(1,2,3) :: List("a", "b", "c") :: List(true, false, true) :: HNil 

object broken extends (HList ~> HList) { 
    def apply[T](n:Int, l:HList): HList = { 
    // I want to pick out the nth element of each HList 
    // so in the above example, if n==1 
    // I want to return 
    // 2 :: "b" :: false :: HNil 
    ??? 
    } 
} 

broken(1,a) 

क्या मैं इस फ़ंक्शन को ठीक कर सकता हूं ताकि यह टिप्पणियों में मैंने जो वर्णन किया है उसके अनुसार काम करता है?

बोनस अंक: क्या मैं इसे एक पुनरावर्तक के रूप में लिख सकता हूं जो मेरे एचएलआईस्ट "ए" को उपरोक्त (इंट, स्ट्रिंग, बूलियन) या समकक्ष एचएलिस्ट के अनुक्रम में बदल देता है?

उत्तर

7

तरीकों से आप ऐसा कर सकता है की एक संख्या हैं, लेकिन मैं एक कस्टम प्रकार वर्ग के साथ जाना चाहते हैं:

import shapeless._ 

trait RowSelect[L <: HList] extends DepFn2[L, Int] { 
    type Row <: HList 
    type Out = Option[Row] 
} 

object RowSelect { 
    def select[L <: HList](l: L, i: Int)(implicit rs: RowSelect[L]): rs.Out = rs(l, i) 

    type Aux[L <: HList, Row0 <: HList] = RowSelect[L] { type Row = Row0 } 

    implicit val hnilRowSelect: Aux[HNil, HNil] = new RowSelect[HNil] { 
    type Row = HNil 
    def apply(l: HNil, i: Int): Option[HNil] = Some(HNil) 
    } 

    implicit def hconsRowSelect[A, T <: HList](implicit 
    trs: RowSelect[T] 
): Aux[List[A] :: T, A :: trs.Row] = new RowSelect[List[A] :: T] { 
    type Row = A :: trs.Row 
    def apply(l: List[A] :: T, i: Int): Option[A :: trs.Row] = for { 
     h <- l.head.lift(i) 
     t <- trs(l.tail, i) 
    } yield h :: t 
    } 
} 

कौन इस तरह काम करता है:

scala> println(RowSelect.select(a, 0)) 
Some(1 :: a :: true :: HNil) 

scala> println(RowSelect.select(a, 1)) 
Some(2 :: b :: false :: HNil) 

scala> println(RowSelect.select(a, 2)) 
Some(3 :: c :: true :: HNil) 

scala> println(RowSelect.select(a, 3)) 
None 

L के लिए एक RowSelect उदाहरण गवाह है कि L सभी List तत्वों के साथ एक सूची है, और एक ऑपरेशन प्रदान करता है जो वैकल्पिक रूप से प्रत्येक List से निर्दिष्ट इंडेक्स पर आइटम का चयन करता है।

आप NatTRel या ConstMapper और ZipWith और एक Poly2 के संयोजन के साथ एक ही बात को पूरा करने में सक्षम होना चाहिए, लेकिन एक कस्टम प्रकार वर्ग सब कुछ एक साथ बंडल अच्छी तरह से और कई मामलों में और अधिक सुविधाजनक compositionality अनुमति देता है।

उदाहरण के लिए, इस मामले में अपने बोनस सवाल का हल बहुत सीधी मामले में RowSelect की लिखित जा सकता है:

def allRows[L <: HList](l: L)(implicit rs: RowSelect[L]): List[rs.Row] = 
    Stream.from(0).map(rs(l, _).toList).takeWhile(_.nonEmpty).flatten.toList 

और फिर:

scala> allRows(a).foreach(println) 
1 :: a :: true :: HNil 
2 :: b :: false :: HNil 
3 :: c :: true :: HNil 

और इसी तरह अगर आप परिवर्तित करना चाहते हैं इन hlists tuples:

def allRows[L <: HList, R <: HList](l: L)(implicit 
    rs: RowSelect.Aux[L, R], 
    tp: ops.hlist.Tupler[R] 
): List[tp.Out] = 
    Stream.from(0).map(rs(l, _).map(tp(_)).toList).takeWhile(_.nonEmpty).flatten.toList 

जो आपको देता है यू:

scala> allRows(a) 
res7: List[(Int, String, Boolean)] = List((1,a,true), (2,b,false), (3,c,true)) 

और इसी तरह।

+0

पॉलिमॉर्फिक कार्यों के बारे में कुछ संबंधित प्रश्न: http://stackoverflow.com/questions/39628068/passing-an-extra-argument-into-a-polymorphic-function http://stackoverflow.com/questions/39628022/using -एक-बहुरूपी-समारोह करने के लिए निकालने-एक वस्तु से-विकल्प –

संबंधित मुद्दे