2016-09-20 1 views
7

각 열이 테이블의 열을 나타내는 HList가 있습니다. HList의 각 목록은 길이가 동일합니다.목록의 H 목록의 N 번째 요소를 선택하고 해당 값을 HList 값으로 반환하십시오.

이 테이블의 개별 행을 튜플 또는 값의 HList로 선택하는 함수를 작성하고 싶습니다. 궁극적으로 이것을 좀 더 현명한 것으로 변환 할 것입니다 (예 : 사례 클래스).

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) 

의견에 설명 된대로 작동하도록이 기능을 수정할 수 있습니까?

보너스 포인트 : 위의 "H"를 (Int, String, Boolean) 또는 동등한 HList 시퀀스로 변환하는 반복기로 작성할 수 있습니까?

답변

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 

RowSelect 예를 L을위한 모든 List 요소를 가진 L은 hlist이고, List에서 지정된 인덱스의 항목을 선택적으로 선택하는 작업을 제공합니다.

당신은 NatTRel 또는 ConstMapperZipWithPoly2의 조합과 같은 일을 수행 할 수 있어야하지만, 사용자 정의 유형 클래스 멋지게 많은 경우에 모든 것을 함께 번들보다 편리하게 구성 할 수 있습니다. 다음

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

그리고 :

는 예를 들어,이 경우 보너스 질문에 대한 해결책은 꽤 노골적 RowSelect의 측면에서 쓸 수

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

을 그리고 유사하게 변환 할 경우 튜플에 대한 이러한 hlists :

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 

u :

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 -a-polymorphic-function-to-extract-an-object-from-options –

관련 문제