Saya memiliki program dengan beberapa kelas kasus. Salah satunya mungkin Person, yang bergantung pada beberapa kelas lain, termasuk yang disebut StemmedString yang penting di sini:

case class Person(name: String, skills: List[Skill], hobbbies: List[StemmedString]
case class Skill(score: Int, title: StemmedString)
case class StemmedString(original: String, stemmed: String)

Sekarang saya ingin dapat menerjemahkan orang ini ke dalam bahasa lain. Untuk melakukan itu, saya ingin pergi dari Person -> List[String]. Itulah daftar string tunggal yang perlu diterjemahkan. Lalu saya ingin KEMBALI dari Daftar[String] -> Orang.

Saya ingin dapat mendefinisikan semua JENIS hal yang harus diterjemahkan, tanpa perlu mengetahui format Person terlebih dahulu, sehingga ini dapat digeneralisasikan pada beberapa kelas kasus yang terdiri dari JENIS yang sama yang dapat diterjemahkan.

Katakanlah apa yang kita terjemahkan adalah semua StemmedString.

Saya dapat LabelledGeneric dan flatMap untuk membuat dua HLlist, salah satu nilai yang akan diterjemahkan, nilai lainnya yang tidak akan diterjemahkan:

trait LowPriorityUnTranslatable extends Poly1 {
  implicit def default[T] = at[T](_ :: HNil)
}

object unTranslatable extends LowPriorityUnTranslatable {
  implicit def caseStemmedString[K, T] = at[FieldType[K, StemmedString]](x => HNil)
  implicit def caseSkill[K, T] = at[FieldType[K, Skill](x => HNil)
}


trait LowPriorityTranslatable extends Poly1 {
  implicit def default[T] = at[T](HNil)
}

object Translatable extends LowPriorityTranslatable {
  implicit def caseStemmedString[K, T] = at[FieldType[K, StemmedString]](_ :: HNil)
  implicit def caseSkill[K, T] = at[FieldType[K, Skill](_ :: HNil)
}

Ini terasa agak bertele-tele, tetapi berfungsi dengan baik. Saya sekarang memiliki dua HLists, dan mereka dapat dengan mudah digabungkan dan dikembalikan ke kelas kasus asli menggunakan align:

val person = Person("...")
val gen = LabelledGeneric[Person] 
val personList = gen.to(person)
val toTranslate = personList flatMap isTranslatable
val notTranslated = personList flatMap unTranslatable    
gen.from((toTranslate ++ notTranslated) align personList)

Ini sangat keren, sekarang yang perlu saya lakukan hanyalah menambahkan langkah terjemahan di tengah. Sangat mudah untuk pergi dari isTranslatable -> List[String] tentu saja, namun saya tidak dapat menemukan cara untuk melakukan ini dengan cara di mana saya dapat kembali lagi. Saya mulai mencoba belajar tentang shapeless karena sepertinya itu adalah alat yang tepat untuk situasi ini, tetapi saya tidak begitu mengerti bagaimana menggunakannya sepenuhnya. Di kepala saya, jika saya dapat menyelesaikan pertanyaan ini, maka saya akan baik-baik saja, tetapi mungkin ada cara yang lebih mudah untuk menggunakan shapeless untuk menyelesaikan masalah ini. Wawasan apa pun akan sangat dihargai!

3
Nandan Rao 31 Juli 2016, 17:29

1 menjawab

Jawaban Terbaik

Jika Anda tidak keberatan menggunakan struktur data yang dapat diubah (dalam hal ini Iterator), Anda dapat menggunakan everything/everywhere untuk solusi yang mudah.

Pertama, kami mengekstrak string yang akan diterjemahkan menggunakan kueri everything; dalam contoh ini kita mengekstrak nilai asli dari objek StemmedString. Daftar tunggal digabungkan menggunakan fungsi Append.

trait TranslatableLP extends Poly1 {
  implicit def default[T] = at[T](_ => Nil: List[String])
}

object Translatable extends TranslatableLP {
  implicit def caseStemmedString = at[StemmedString](s => List(s.original))
}

object Append extends Poly2 {
  implicit val caseString = at[List[String], List[String]](_ ++ _)
}

val strings = everything(Translatable)(Append)(person)

Sekarang kita menerjemahkan string:

def translate(s: String): String = ???

val translatedStrings = strings.map(translate)

Dan akhirnya kita dapat memetakan objek StemmedString menggunakan string yang diterjemahkan menggunakan everywhere:

object Update extends Poly1 {
  def iterator = translatedStrings.iterator
  implicit def caseStemmedString = at[StemmedString](_.copy(original = iterator.next))
}

val translated = everywhere(Update)(person)

Ketika saya menemukan waktu, saya akan mencoba menemukan solusi yang lebih bersih hanya dengan menggunakan struktur data yang tidak dapat diubah.

1
devkat 2 Agustus 2016, 17:02
Cantik! Akan sangat tertarik untuk melihat versi dengan hanya struktur data yang tidak dapat diubah jika Anda dapat menemukan waktunya!
 – 
Nandan Rao
2 Agustus 2016, 20:37