2016-07-26 4 views
1

Невозможно получить foldLeft, работая над HList, когда складывается в список, когда я сбрасываю Hlist на строку, все работает нормально.Shapeless: foldLeft на ошибке компиляции hlist

object wrapInList extends Poly1 { 
    implicit def intCase = at[Int]{v => List(v)} 
    implicit def stringCase = at[String]{v => List(v)} 
} 

object mergeToString extends Poly1 { 
    implicit def intCase = at[Int](_.toString()) 
    implicit def stringCase = at[String](identity) 
} 

object foldListPoly extends Poly2 { 
    implicit def foldToList[T](implicit st: wrapInList.Case.Aux[T, List[T]]) = 
    at[List[T], T]{ (acc, t) => acc ::: wrapInList(t) } 
    implicit def foldToString[T](implicit st: mergeToString.Case.Aux[T, String]) = 
    at[String, T]{ (acc, t) => acc + mergeToString(t)} 
} 

val hList = "aoeu" :: 42 :: HNil 
val foldedHlist = hList.foldLeft("")(foldListPoly) 
val foldedHList2 = hList.foldLeft(Nil)(foldListPoly) 

Erorr по составлению foldedHList2

could not find implicit value for parameter folder: 
shapeless.ops.hlist.LeftFolder[shapeless.::[String,shapeless.::[Int,shapeless.HNil]],scala.collection.immutable.Nil.type,com.test.Test.foldListPoly.type] 
+1

Вы можете добавить ошибку? –

+0

Я обновил вопрос с ошибкой компиляции. – andresrcom

ответ

2

Пожалуйста, обратите внимание, что бесформенный определяет метод runtimeList на HList, который эффективно вычисляет List[Any] от HList, а также метод toList, который преобразует HList в более точно напечатанный List. Тем не менее, интересно посмотреть, как эта операция может быть выполнена с использованием fold.

Здесь есть несколько морщин. Первое, что нужно учитывать, это то, что тип List, который вы накапливаете здесь, должен быть. Скорее всего, вы хотели бы, чтобы тип элемента результирующего списка был наименьшей верхней границей (LUB) типов элементов HList, которые вы складываете. Чтобы получить результат этого типа, нам нужно вычислить LUB по мере продвижения.

Мы также должны разместить Nil в качестве начального значения. Nil - это значение типа List[Nothing], и это проблематично в тех случаях, когда нам необходимо разрешить неявное индексирование по List[T]. Переменная типа T должна быть описана в Nothing в соответствии с типом Nil, но, к сожалению, тип inferencer типа Scala относится к типу Nothing как значение переменной типа как «нерешенное» ... результатом этого является неявное разрешение провалится ложно. Чтобы обойти эту проблему, мы должны предоставить явный случай foldListPoly для Nil.type.

Сведя вместе мы в конечном итоге,

object wrapInList extends Poly1 { 
    implicit def default[T] = at[T]{v => List(v)} 
} 

object foldListPoly extends Poly2 { 
    implicit def foldToListNil[U](implicit st: wrapInList.Case.Aux[U, List[U]]) = 
    at[Nil.type, U]{ (acc, u) => wrapInList(u) } 

    implicit def foldToList[T, U, L, LL](
    implicit st: wrapInList.Case.Aux[U, List[U]], 
    lub: Lub[T, U, L], 
    llub: Lub[List[T], List[U], LL], 
    ev: LL =:= List[L] 
) = at[List[T], U]{ (acc, u) => llub.left(acc) ::: llub.right(wrapInList(u)) } 
} 

scala> ("aoeu" :: 42 :: HNil).foldLeft(Nil)(foldListPoly) 
res0: List[Any] = List(aoeu, 42) 

scala> (13 :: 23 :: HNil).foldLeft(Nil)(foldListPoly) 
res1: List[Int] = List(13, 23) 

scala> (23 :: true :: HNil).foldLeft(Nil)(foldListPoly) 
res2: List[AnyVal] = List(23, true) 

Обратите внимание, что в каждом случае тип элемента полученного списка является LUB типов элементов в HList.

0

Проблема заключается в том, что вы генерируете List[String] для "aoeu" в wrapInList, который не совместим со следующим элементом hList (42, который Int). Если вы можете жить с List[Any] (в противоположность верхняя граница), вы можете сделать это следующим образом:

object wrapInList extends Poly1 { 
    implicit def intCase = at[Int]{v => List[Any](v)} 
    implicit def stringCase = at[String]{v => List[Any](v)} 
} 

object foldListPoly extends Poly2 { 
    implicit def foldToList[T](implicit st: wrapInList.Case.Aux[T, List[Any]]) = 
    at[List[Any], T]{ (acc, t) => acc ::: wrapInList(t) } 
} 

Кроме того, вы должны явно ввести Nil в List[Any]:

val foldedHList2 = hList.foldLeft(Nil:List[Any])(foldListPoly) 
+0

У меня возникла идея несовместимых типов, но, к сожалению, этот код не компилируется и дает ту же ошибку при попытке свернуть по 'hList'. – andresrcom

+0

Извините, я забыл включить вызов метода, который включает в себя тип 'List [Any]'. – devkat

Смежные вопросы