Как извлечь типы из кортежа, который реализует класс типов - PullRequest
0 голосов
/ 02 апреля 2020

Функция a может принимать один аргумент или кортеж, эти аргументы должны быть членами класса типов StringIdentifiable

Как извлечь и разложить тип кортежа на типы, которые также имеют экземпляры класса типов

@typeclass trait StringIdentifiable[M] {
  def identify(id: M): String
}

def a[K: StringIdentifiable] (k:K){
 k match{
case (k1) => 
 implicitly[StringIdentifiable[K]].identify(k1)
case (k1,k2) =>
 implicitly[StringIdentifiable[k1.type]].identify(k1) 
 implicitly[StringIdentifiable[k2.type]].identify(k2)
}

Я получаю ошибку во втором матче:

Could not find an instance of StringIdentifiable for k1.type

Ответы [ 2 ]

2 голосов
/ 02 апреля 2020

k1.type, k2.type - одноэлементные типы. Попробуйте

@typeclass trait StringIdentifiable[M] {
  def identify(id: M): String
}

object StringIdentifiable {
  implicit def one[K]: StringIdentifiable[K] = ???

  implicit def two[K1: StringIdentifiable, K2: StringIdentifiable]: StringIdentifiable[(K1, K2)] = {
    new StringIdentifiable[(K1, K2)] {
      override def identify(id: (K1, K2)): String = id match {
        case (k1,k2) =>
          implicitly[StringIdentifiable[K1]].identify(k1)
          implicitly[StringIdentifiable[K2]].identify(k2)
          ???
      }
    }
  }
}

def a[K: StringIdentifiable](k:K): String = implicitly[StringIdentifiable[K]].identify(k)
1 голос
/ 02 апреля 2020

Вы можете сделать это с бесформенным. Например:

import shapeless._, ops.hlist._

object MyPoly extends Poly2 { 
  implicit def foo[A] = at[A, StringIdentifiable[A]]( (a, f) => f.identify(a) ) 
}

def a[K: StringIdentifiable, L <: HList, O <: HList](k: K)(
  implicit 
  gen: Generic.Aux[K, L], // decompose K into HList L
  lift: LiftAll.Aux[StringIdentifiable, L, O], // find an instance of StringIdentifiable for every element of L
  zip: ZipWith[L, O, MyPoly.type] // zip L with its typeclass instances and map the results with the polymorphic function MyPoly
): String :: zip.Out = { 
  val l = gen.to(k)
  val o = lift.instances
  implicitly[StringIdentifiable[K]].identify(k) :: zip(l, o) 
}

implicit def id1[A,B]: StringIdentifiable[(A, B)] = _ => "1"
implicit val id2: StringIdentifiable[String] = _ => "2"
implicit val id3: StringIdentifiable[Int] = _ => "3"

a(("foo", 42)) // 1 :: 2 :: 3 :: HNil

Полное решение вашей проблемы (IIU C), вероятно, состоит в использовании бесформенного для автоматической генерации StringIdentifiable экземпляров для всех кортежей.

trait StringIdentifiable[M] {
  def identify(id: M): String
}
object StringIdentifiable {
  object MyPoly extends Poly2 { 
     implicit def foo[A] = at[A, StringIdentifiable[A]]( (a, f) => f.identify(a) ) 
  }

  implicit def mkSI[K, L <: HList, O <: HList](
    implicit
    tup: IsTuple[K],
    gen: Generic.Aux[K, L],
    lift: LiftAll.Aux[StringIdentifiable, L, O],
    zip: ZipWith[L, O, MyPoly.type]
  ): StringIdentifiable[K] = { 
    val o = lift.instances
    k => {
      val l = gen.to(k)
      zip(l, o).mkString("(", ", ", ")")
    }
  }
}
...