Как прочитать элемент из Scala HList?

Существует очень мало читаемой документации о HLists, и ответы, которые я могу найти на SO, приходят из космоса для скромного новичка в Scala.

Я столкнулся с HLlists, потому что Slick может автоматически генерировать некоторые из них для представления строк базы данных. Они slick.collection.heterogeneous.HList (не бесформенные). Пример:

type MyRow = HCons[Int,HCons[String,HCons[Option[String],HCons[Int,HCons[String,HCons[Int,HCons[Int,HCons[Option[Int],HCons[Option[Float],HCons[Option[Float],HCons[Option[String],HCons[Option[String],HCons[Boolean,HCons[Option[String],HCons[Option[String],HCons[Option[String],HCons[Option[String],HCons[Option[String],HCons[Option[Int],HCons[Option[Float],HCons[Option[Float],HCons[Option[Float],HCons[Option[String],HCons[Option[String],HNil]]]]]]]]]]]]]]]]]]]]]]]]
def MyRow(a, b, c, ...): MyRow = a :: b :: c :: ... :: HNil

Теперь, учитывая одну из этих строк, мне нужно прочитать один элемент, если это возможно, напечатать. Я просто не могу этого сделать. Я старался

row(4)  // error
row._4  // error
row.toList  // elements are inferred as Any
row match { case a :: b :: c :: x :: rest => x }  // "Pattern type is incompatible. Expected MyRow."
row match { case MyRow(_,_,_,_,_,x,...) => x }  // is not a case class like other rows
row match { HCons[Int,HCons[String,HCons[Option[String],HCons[Int,HCons[String, x]]]]] => x.head }  // error
row.tail.tail.tail.tail.head  // well, is that really the way??

Может кто-нибудь объяснить, как я могу извлечь определенное значение из этого динозавра?


person JulienD    schedule 13.01.2017    source источник
comment
что...... dinosaur.... Кажется, вы в ужасе от HList.   -  person sarveshseri    schedule 13.01.2017
comment
@SarveshKumarSingh не нужно высказывать мнения, отражающие характер человека, которого вы не знаете. Могу ли я предложить вам удалить этот комментарий?   -  person maasg    schedule 13.01.2017


Ответы (2)


Я ожидаю, что ваш row(0) поиск будет работать на основе документ HList API для apply. Вот пример, который я пробовал с Slick 3.1.1:

scala> import slick.collection.heterogeneous._
import slick.collection.heterogeneous._

scala> import slick.collection.heterogeneous.syntax._
import slick.collection.heterogeneous.syntax._

scala> type MyRow = Int :: String :: HNil
defined type alias MyRow

scala> val row: MyRow = 1 :: "a" :: HNil
row: MyRow = 1 :: a :: HNil

scala> row(0) + 99
res1: Int = 100

scala> val a: String = row(1)
a: String = a
person Richard Dallaway    schedule 15.01.2017
comment
Я попробовал этот новый импорт, и для меня row(0) имеет тип Any, хотя row.head имеет тип Int. - person JulienD; 16.01.2017
comment
О, подождите, IntelIJ подчеркивает это как ошибку (Any не соответствует ожидаемому типу Int), но на самом деле компилируется. Хотя я не понимаю, как это возможно. - person JulienD; 16.01.2017
comment
Две вещи: результатом row(0) является псевдоним типа, который в конечном итоге является Int, и может случиться так, что IntelliJ смущает это. Кроме того: для выяснения этого используется макрос, который может быть источником путаницы в IntelliJ - я не знаю :-( Кроме того, если вы используете значение времени выполнения (например, val n=0; row(n) в отличие от литерала, такого как row(0)) Думаю, у вас получится Any. - person Richard Dallaway; 16.01.2017
comment
Я понимаю. Еще одна вещь: у вас есть какие-либо идеи, почему это другое решение val a: String = row.drop(1).head не работает? (HList#Head не соответствует ожидаемому типу String и на этот раз не компилируется). - person JulienD; 16.01.2017
comment
Извините, я не знаю. Я предлагаю открыть новый вопрос SO по этому поводу, - person Richard Dallaway; 16.01.2017

Только одно... если это не слишком важно, просто придерживайтесь HList как type. Не делайте alias это до MyRow без необходимости.

Итак.. у вас было

val row = a :: b :: c :: ... :: HNil

Как насчет этого ?

val yourX = row match { case a :: b :: c :: x ::: rest => x }

обратите внимание, что ::: вместо :: в конце.

Или... как насчет этого,

val yourX = row.tail.tail.tail.head

// this may change a little if you had,
def MyRow(a, b, c, ...): MyRow = a :: b :: c :: ... :: HNil

val row = MyRow(a, b, c, ...)

val yourX = row.asInstanceOf[HList].tail.tail.tail.head
person sarveshseri    schedule 13.01.2017
comment
Sbt говорит, что не может разрешить символ ':::' . Второе решение - это то, что я использую в данный момент, просто представьте, что мне нужны элементы 12, 14, 15, 17, 26 и 27... Но если нет другого решения, я оставлю его. - person JulienD; 13.01.2017
comment
Это ::: действительно есть в скаладоках, но я не могу заставить его работать при сопоставлении с образцом. Должен быть способ использовать .drop вместо .tail.tail.tail..., но я тоже не смог заставить его работать. Спасибо за ответ. - person JulienD; 16.01.2017