2017-01-28 4 views
3

Я пытаюсь сделать это сушилку:Deterimine конкретного типа без явного согласования

type CollectPredicate = PartialFunction[Option[SqlArgument], SQLActionBuilder] 

val cp: CollectPredicate = { 
    case Some(lc: LanguageCode) => buildSql(lc) 
    case Some(bh: BlobHashs) => buildSql(bh) 
    case Some(lsi: LastSeenId) => buildSql(lsi) 
    } 

Я хочу найти способ сделать что-то вроде:

type args = LanguageCode :+: BlobHashs :+: LastSeenId :+: CNil 

val PlacesRequestType = Coproduct[args] 

val cp = (sq: args) => buildSql(PlacesRequestType(sql)) 

Это buildSql:

def buildSql[T, A](args: T)(implicit sqlArgument: SqlArgumentBuilder[T, A], sp: SetParameter[A]): SQLActionBuilder = { 
    sqlArgument.sql(args) 
    } 

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

+0

ли 'cp' должны быть' PartialFunction'? Или ваша цель просто иметь общий метод/функцию, которая передает свой аргумент на 'buildSql'? –

+0

Не нужно быть 'PartialFunction', общая функция была бы еще лучше – raam86

ответ

1

Это, вероятно, дольше, чем вы ожидали, но я думаю, что так оно и должно выглядеть.

Таким образом, в методе generic мы получаем общее представление SqlArgument, которое является экземпляром только одного из конкретных подтипов SqlArgument. В вашем случае LanguageCode :+: BlobHashs :+: LastSeenId :+: CNil. Чтобы определить, из какого типа наш экземпляр на самом деле, мы передаем это общее представление в значение implicit, предоставленное coproduct, и мы переходим рекурсивно в виде хвоста.

В вашем случае H = LanguageCode и T = BlobHashs :+: LastSeenId :+: CNil. Если наш экземпляр имеет тип LanguageCode, он будет соответствовать первому случаю. Если он другого типа, он будет проходить рекурсивно с хвостом. То есть H = BlobHashs и T = LastSeenId :+: CNil и так далее ....

import shapeless.{Generic, Coproduct, Inr, Inl, CNil, :+:} 

trait cp[T] { 
    def apply(t: T): SQLActionBuilder 
} 

object cp { 
    def apply(a: SqlArgument)(implicit cp: cp[SqlArgument]) = cp(a) 

    def pure[T](f: T => SQLActionBuilder) = new cp[T] { 
    def apply(t: T) = f(t) 
    } 

    implicit def generic[Co <: Coproduct](implicit gen: Generic.Aux[SqlArgument, Co], cp: cp[Co]): cp[SqlArgument] = pure { 
    sql => cp(gen.to(sql)) 
    } 

    implicit val cnil: cp[CNil] = pure(_ => throw new Exception("Impossible!")) 

    implicit def coproduct[H, T <: Coproduct, A](implicit cp: cp[T], 
                 b: SqlArgumentBuilder[H, A], 
                 sp: SetParameter[A]): cp[H:+:T] = pure { 
    case Inl(h) => buildSql(h) 
    case Inr(t) => cp(t) 
    } 
} 
+0

спасибо, что потратили время на это, я пробовал использовать его вот так: ' import cp._; val q = cp (PlaceIds (List (1,2,3))), но я получаю 'Ошибка: (207, 13) не удалось найти неявное значение для параметра cp: net.findhotel.zedek.core.data. SqlWriter.cp [net.findhotel.zedek.core.models.Payloads.SqlArgument] val q = cp (PlaceIds (List (1,2,3))) 'Что странно, так как я вижу здесь рекурсивную конструкцию, которая должна раскрывать это – raam86

+0

@ raam86 вы могли бы повторно запустить его с помощью опции компилятора '-Xlog-implicits' или с помощью плагина-компилятора [splain] (https://github.com/tek/splain/) и опубликовать полную скрытую не найденную цепочку здесь ? – teldosas

+0

Спасибо, что помогло, он жалуется на запечатанные классы черт/дел, поэтому я полагаю, что мне нужно немного поправить свое решение, чтобы это работало – raam86

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