Implicit parameter precedence - scala

I was trying to convert generic type to HList:
trait ToHList[T] {
type Out <: HList
def apply(value: T): Out
}
trait LowPriorityToHList {
implicit def default[T]: ToHList.Aux[T, T :: HNil] =
new ToHList[T] {
override type Out = T :: HNil
override def apply(value: T): T :: HNil = value :: HNil
}
}
object ToHList extends LowPriorityToHList {
type Aux[T, Out0] = ToHList[T] { type Out = Out0 }
def apply[T](implicit toHList: ToHList[T]): Aux[T, toHList.Out] = toHList
implicit def toHList[T, Repr <: HList, N <: Nat](implicit
gen: Generic.Aux[T, Repr],
len: Length.Aux[Repr, N],
lt: LT[Nat._0, N]): ToHList.Aux[T, Repr] =
new ToHList[T] {
override type Out = Repr
override def apply(value: T): Repr = gen.to(value)
}
}
object Main extends App {
println(ToHList.apply[Int].apply(1)) // expected 1 :: HNil
println(ToHList.apply[(Int, Int)].apply((1, 2))) // expected 1 :: 2 :: HNil
}
I intended to give priority to ToHList.toHList over ToHList.default but
this code cause following compilation error:
[error] ToHList.scala:39:24: ambiguous implicit values:
[error] both method toHList in object ToHList of type [T, Repr <: shapeless.HList, N <: shapeless.Nat](implicit gen: shapeless.Generic.Aux[T,Repr], implicit len: shapeless.ops.hlist.Length.Aux[Repr,N], implicit lt: shapeless.ops.nat.LT[shapeless.Nat._0,N])ToHList.Aux[T,Repr]
[error] and method default in trait LowPriorityToHList of type [T]=> ToHList.Aux[T,T :: shapeless.HNil]
[error] match expected type ToHList[(Int, Int)]
[error] println(ToHList.apply[(Int, Int)].apply((1, 2))) // expected 1 :: 2 :: HNil
I want to give priority to ToHList.toHList over ToHList.default.
How can I fix this error?

If both toHList and default are applicable then they have the same priority, so they make ambiguity. Indeed, although default is defined in a low-priority super-trait but it's more specific than toHList. See details in Why is this implicit ambiguity behaviour happening?
So there is no reason to put default into a low-priority super-trait, this will not make desired impact. But if you put toHList and default into the same object, default will win as more specific. And from expected 1 :: 2 :: HNil it seems you want vice versa toHList to win. You can use shapeless.LowPriority
object ToHList {
type Aux[T, Out0] = ToHList[T] { type Out = Out0 }
def apply[T](implicit toHList: ToHList[T]): Aux[T, toHList.Out] = toHList
implicit def toHList[T, Repr <: HList, N <: Nat](implicit
gen: Generic.Aux[T, Repr],
len: Length.Aux[Repr, N],
lt: LT[Nat._0, N]
): ToHList.Aux[T, Repr] =
new ToHList[T] {
override type Out = Repr
override def apply(value: T): Repr = gen.to(value)
}
implicit def default[T](implicit
lowPriority: LowPriority
): ToHList.Aux[T, T :: HNil] =
new ToHList[T] {
override type Out = T :: HNil
override def apply(value: T): T :: HNil = value :: HNil
}
}
Alternatively in this specific case you can use shapeless.Refute, shapeless.OrElse
implicit def default[T](implicit
orElse: OrElse[Refute[Generic[T]], Generic.Aux[T, HNil]]
): ToHList.Aux[T, T :: HNil] =
new ToHList[T] {
override type Out = T :: HNil
override def apply(value: T): T :: HNil = value :: HNil
}

Related

Scala case classes and recursive reflection

Given 2 Scala case classes
case class Bar(x: Int)
case class Foo(b: Bar, z: Double)
I have a piece of code that prints the types of Foo fields using reflection:
import scala.reflect.runtime.universe._
def f[T: TypeTag] = typeOf[T].members.filter(!_.isMethod)
and I call it like f[Foo] and f[Bar]. Calling the former returns a List[Type] as [Bar, Double].
How can I call f on the first element of the list? Equivalently, how can I print types recursively when Foo has a custom class Bar? Equivalently how can I get from Bar as Type a Bar.type?
Many thanks
You don't actually need the type variable T in f. You can define it like this (as Dima suggested in the comments):
def f(t: Type) =
t.members.filter(!_.isMethod).map(_.typeSignature)
To use this to recursively print a type:
def printTypesRecursive(t: Type, prefix: String = ""): Unit = {
println(prefix + t)
f(t).foreach(printTypesRecursive(_, prefix + " "))
}
printTypesRecursive(typeOf[Foo])
Output:
Foo
Double
Bar
Int
Equivalently how can I get from Bar as Type a Bar.type?
Bar.type is the type of companion object
Class companion object vs. case class itself
I need something like f[f[Foo].head]
I guess you have here some confusion between compile-time and runtime
Runtime vs. Compile time
You can call
def f[T: TypeTag] = typeOf[T].members.filter(!_.isMethod)
f[Foo]
//Scope{
// private[this] val z: <?>;
// private[this] val b: <?>
//}
if you know type T statically i.e. at compile time (earlier).
You can call
def f_dyn(tpe: Type) = tpe.members.filter(!_.isMethod)
f_dyn(typeOf[Foo])
//Scope{
// private[this] val z: <?>;
// private[this] val b: <?>
//}
if you know type tpe dynamically i.e. at runtime (later).
You can express f via f_dyn
def f[T: TypeTag] = f_dyn(typeOf[T])
def f_dyn(tpe: Type) = tpe.members.filter(!_.isMethod)
If you want to iterate the method (apply it recursively) then it should return something like it accepts, i.e. now this is types rather than symbols, so you need to add somewhere something like .typeSignature, .asMethod.returnType, .asType.toType. Also maybe now you're more interested in .decls rather than .members since you are not looking for inherited members. Also .decls returns field symbols in correct order on contrary to .members. Finally let it be better List[...] rather than raw Scope (.toList)
def f[T: TypeTag]: List[Type] = f_dyn(typeOf[T])
def f_dyn(tpe: Type): List[Type] =
tpe.decls.filter(!_.isMethod).map(_.typeSignature).toList
f_dyn(f[Foo].head) // List(Int)
f_dyn(f_dyn(typeOf[Foo]).head) // List(Int)
You can iterate f_dyn
f_dyn(typeOf[Foo]) // List(Bar, Double)
f_dyn(typeOf[Foo]).map(f_dyn) // List(List(Int), List())
f_dyn(typeOf[Foo]).map(f_dyn).map(_.map(f_dyn)) // List(List(List()), List())
If you really want to iterate f rather than f_dyn then the complication is that you can call f[T] for the second time only on a statically known type T but you have the type that is the result of the first call only at runtime, you don't have it at compile time. In principle you can use runtime compilation (creating new compile time inside runtime) although this can work slower than ordinary reflection and doesn't seem needed now
import scala.reflect.runtime.{currentMirror => rm}
import scala.tools.reflect.ToolBox // libraryDependencies += scalaOrganization.value % "scala-compiler" % scalaVersion.value
val tb = rm.mkToolBox()
// suppose f is defined in object App
tb.eval(q"App.f[${f[Foo].head}]") // List(Int)
tb.eval(q"""
import App._
f[${f[Foo].head}]
""")
// List(Int)
Now all the classes Foo, Bar... are defined at compile time so it would make sense to use compile-time reflection (macros) rather than runtime reflection
Getting Case Class definition which points to another Case Class
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def f[T]: List[String] = macro Macros.f_impl[T]
def f1[T]: List[List[String]] = macro Macros.f1_impl[T]
def f2[T]: List[List[List[String]]] = macro Macros.f2_impl[T]
class Macros(val c: blackbox.Context) {
import c.universe._
def f_dyn(tpe: Type): List[Type] =
tpe.decls.filter(!_.isMethod).map(_.typeSignature).toList
val ListObj = q"_root_.scala.List"
val ListT = tq"_root_.scala.List"
val StringT = tq"_root_.scala.Predef.String"
def f_impl[T: WeakTypeTag]: Tree = {
val types: List[Type] = f_dyn(weakTypeOf[T])
val typeStrings: List[String] = types.map(_.toString)
q"$ListObj.apply[$StringT](..$typeStrings)"
}
def f1_impl[T: WeakTypeTag]: Tree = {
val types: List[List[Type]] = f_dyn(weakTypeOf[T]).map(f_dyn)
val typeStrings: List[List[String]] = types.map(_.map(_.toString))
q"$ListObj.apply[$ListT[$StringT]](..$typeStrings)"
}
def f2_impl[T: WeakTypeTag]: Tree = {
val types: List[List[List[Type]]] =
f_dyn(weakTypeOf[T]).map(f_dyn).map(_.map(f_dyn))
val typeStrings: List[List[List[String]]] = types.map(_.map(_.map(_.toString)))
q"$ListObj.apply[$ListT[$ListT[$StringT]]](..$typeStrings)"
}
}
// in a different subproject
f[Foo]
//scalac: _root_.scala.List.apply[_root_.scala.Predef.String]("Bar", "Double")
f1[Foo]
//scalac: _root_.scala.List.apply[_root_.scala.List[_root_.scala.Predef.String]](scala.collection.immutable.List("Int"), scala.collection.immutable.List())
f2[Foo]
//scalac: _root_.scala.List.apply[_root_.scala.List[_root_.scala.List[_root_.scala.Predef.String]]](scala.collection.immutable.List(scala.collection.immutable.List()), scala.collection.immutable.List())
The runtime of macros (when they are expanded) is the compile time of main code.
Do macros support annotations too? like can I access my case class annotations with macros? with runtime reflection , i would do symbolOf[Foo].asClass.annotations
Yes, surely.
def foo[T]: Unit = macro fooImpl[T]
def fooImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
println(symbolOf[T].asClass.annotations)
q"()"
}
class myAnnot extends StaticAnnotation
#myAnnot
case class Foo(b: Bar, z: Double)
symbolOf[Foo].asClass.annotations // at runtime: List(myAnnot)
foo[Foo]
// at compile time with scalacOptions += "-Ymacro-debug-lite":
// scalac: List(myAnnot)
One more option to perform compile-time calculations is to use one of libraries encapsulating work with macros e.g. Shapeless
// libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.10"
import shapeless.{::, DepFn0, DepFn1, HList, HNil, Generic, Poly0, Poly1, Typeable, poly}
trait DeepGeneric[T <: Product] {
type Repr <: HList
def to(t: T): Repr
def from(r: Repr): T
}
object DeepGeneric {
type Aux[T <: Product, Repr0 <: HList] = DeepGeneric[T] {type Repr = Repr0}
def instance[T <: Product, Repr0 <: HList](f: T => Repr0, g: Repr0 => T): Aux[T, Repr0] = new DeepGeneric[T] {
override type Repr = Repr0
override def to(t: T): Repr = f(t)
override def from(r: Repr): T = g(r)
}
implicit def deepGeneric[A <: Product, L <: HList, L1 <: HList](implicit
generic: Generic.Aux[A, L],
hListDeepGeneric: HListDeepGeneric.Aux[L, L1]
): Aux[A, L1] = instance(a => hListDeepGeneric.to(generic.to(a)), l1 => generic.from(hListDeepGeneric.from(l1)))
}
trait HListDeepGeneric[T <: HList] {
type Repr <: HList
def to(t: T): Repr
def from(r: Repr): T
}
trait LowPriorityHListDeepGeneric {
type Aux[T <: HList, Repr0 <: HList] = HListDeepGeneric[T] {type Repr = Repr0}
def instance[T <: HList, Repr0 <: HList](f: T => Repr0, g: Repr0 => T): Aux[T, Repr0] = new HListDeepGeneric[T] {
override type Repr = Repr0
override def to(t: T): Repr = f(t)
override def from(r: Repr): T = g(r)
}
implicit def headNotCaseClass[H, T <: HList, T_hListDeepGen <: HList](implicit
tailHListDeepGeneric: HListDeepGeneric.Aux[T, T_hListDeepGen]
): Aux[H :: T, H :: T_hListDeepGen] = instance({
case h :: t => h :: tailHListDeepGeneric.to(t)
}, {
case h :: t => h :: tailHListDeepGeneric.from(t)
})
}
object HListDeepGeneric extends LowPriorityHListDeepGeneric {
implicit val hNil: Aux[HNil, HNil] = instance(identity, identity)
implicit def headCaseClass[H <: Product, T <: HList, H_deepGen <: HList, T_hListDeepGen <: HList](implicit
headDeepGeneric: DeepGeneric.Aux[H, H_deepGen],
tailHListDeepGeneric: HListDeepGeneric.Aux[T, T_hListDeepGen]
): Aux[H :: T, H_deepGen :: T_hListDeepGen] = instance({
case h :: t => headDeepGeneric.to(h) :: tailHListDeepGeneric.to(t)
}, {
case h :: t => headDeepGeneric.from(h) :: tailHListDeepGeneric.from(t)
})
}
trait DeepMapper[P <: Poly1, In <: HList] extends DepFn1[In] {
type Out <: HList
}
trait LowPriorityDeepMapper {
type Aux[P <: Poly1, In <: HList, Out0 <: HList] = DeepMapper[P, In] {type Out = Out0}
def instance[P <: Poly1, In <: HList, Out0 <: HList](f: In => Out0): Aux[P, In, Out0] = new DeepMapper[P, In] {
override type Out = Out0
override def apply(t: In): Out = f(t)
}
implicit def headNotHList[P <: Poly1, H, T <: HList](implicit
headCase: poly.Case1[P, H],
tailDeepMapper: DeepMapper[P, T]
): Aux[P, H :: T, headCase.Result :: tailDeepMapper.Out] =
instance(l => headCase(l.head) :: tailDeepMapper(l.tail))
}
object DeepMapper extends LowPriorityDeepMapper {
implicit def hNil[P <: Poly1]: Aux[P, HNil, HNil] = instance(_ => HNil)
// implicit def headHList[P <: Poly1, H <: HList, H_deepMap <: HList, T <: HList](implicit
// headDeepMapper: DeepMapper.Aux[P, H, H_deepMap],
// headCase: poly.Case1[P, H_deepMap], // apply poly one more time
// tailDeepMapper: DeepMapper[P, T]
// ): Aux[P, H :: T, headCase.Result :: tailDeepMapper.Out] =
// instance(l => headCase(headDeepMapper(l.head)) :: tailDeepMapper(l.tail))
implicit def headHList[P <: Poly1, H <: HList, T <: HList](implicit
headDeepMapper: DeepMapper[P, H], // don't apply poly one more time
tailDeepMapper: DeepMapper[P, T]
): Aux[P, H :: T, headDeepMapper.Out :: tailDeepMapper.Out] =
instance(l => headDeepMapper(l.head) :: tailDeepMapper(l.tail))
}
trait DeepFillWith[P <: Poly0, L <: HList] extends DepFn0 {
type Out = L
}
trait LowPriorityDeepFillWith {
def apply[P <: Poly0, L <: HList](implicit deepFillWith: DeepFillWith[P, L]): DeepFillWith[P, L] = deepFillWith
def instance[P <: Poly0, L <: HList](f: => L): DeepFillWith[P, L] = new DeepFillWith[P, L] {
override def apply(): L = f
}
implicit def headNotHList[P <: Poly0, H, T <: HList](implicit
headCase: poly.Case0.Aux[P, H],
tailDeepFillWith: DeepFillWith[P, T]
): DeepFillWith[P, H :: T] =
instance(headCase() :: tailDeepFillWith())
}
object DeepFillWith extends LowPriorityDeepFillWith {
implicit def hNil[P <: Poly0]: DeepFillWith[P, HNil] = instance(HNil)
implicit def headHList[P <: Poly0, H <: HList, T <: HList](implicit
headDeepFillWith: DeepFillWith[P, H],
tailDeepFillWith: DeepFillWith[P, T]
): DeepFillWith[P, H :: T] =
instance(headDeepFillWith() :: tailDeepFillWith())
}
// needed if DeepMapper "applies poly one more time",
// e.g. for field NAMES and types (via DeepLabelledGeneric), not just types (via DeepGeneric)
// trait LowPriorityTypeablePoly extends Poly1 {
// implicit def notHListCase[V](implicit typeable: Typeable[V]): Case.Aux[V, String] =
// at(_ => typeable.describe)
// }
//
// object typeablePoly extends LowPriorityTypeablePoly {
// implicit def hListCase[V <: HList]: Case.Aux[V, V] = at(identity)
// }
object typeablePoly extends Poly1 {
implicit def cse[A](implicit typeable: Typeable[A]): Case.Aux[A, String] =
at(_ => typeable.describe)
}
object nullPoly extends Poly0 {
implicit def cse[A]: Case0[A] = at(null.asInstanceOf[A])
}
def classFieldTypes[T <: Product] = new PartiallyApplied[T]
class PartiallyApplied[T <: Product] {
def apply[L <: HList]()(implicit
deepGeneric: DeepGeneric.Aux[T, L],
deepFillWith: DeepFillWith[nullPoly.type, L],
deepMapper: DeepMapper[typeablePoly.type, L],
): deepMapper.Out = deepMapper(deepFillWith())
}
classFieldTypes[Bar]() // Int :: HNil
classFieldTypes[Foo]() // (Int :: HNil) :: Double :: HNil
Generic/LabelledGeneric/DeepGeneric, Mapper/DeepMapper, FillWith/DeepFillWith, Typeable are type classes.
lets say for each Type I want the code to behave differently, if Double do x, if Int do y.
You can use types comparisons t =:= typeOf[Double], t <:< typeOf[Double] if you use runtime/compile-time reflection or you can keep using type classes and polymorphic functions
trait MyTypeclass[T] {
def apply(): Unit
}
object MyTypeclass {
implicit val double: MyTypeclass[Double] = () => println("do x")
implicit val int: MyTypeclass[Int] = () => println("do y")
implicit def caseClass[T <: Product, L <: HList](implicit
deepGeneric: DeepGeneric.Aux[T, L],
deepFillWith: DeepFillWith[nullPoly.type, L],
deepMapper: DeepMapper[myPoly.type, L]
): MyTypeclass[T] = () => deepMapper(deepFillWith())
}
object myPoly extends Poly1 {
implicit def cse[T: MyTypeclass]: Case.Aux[T, Unit] = at(_ => foo)
}
def foo[T](implicit tc: MyTypeclass[T]): Unit = tc()
foo[Int]
// do y
foo[Double]
// do x
foo[Foo]
// do y
// do x
foo[Bar]
// do y
Shapeless is also capable of handling annotations
import shapeless.Annotation
implicitly[Annotation[myAnnot, Foo]].apply() // myAnnot#1a3869f4

Shapeless Example on computing deltas type mismatch error

I am trying to replicate the example from the Shapeless-Easy talk (https://www.youtube.com/watch?v=JKaCCYZYBWo). The code for it can be found here: https://harrylaou.com/scala/shapeless/deltas/
Alternatively please see below for
sealed trait Diff[A]
final case class Identical[A](value: A) extends Diff[A]
final case class Different[A](left: A, right: A) extends Diff[A]
object Diff {
def apply[A](left: A, right: A): Diff[A] =
if (left == right) Identical(left)
else Different(left, right)
}
trait SimpleDelta[R <: HList] extends DepFn2[R, R] {
type Out <: HList //Result is bounded by HList
}
object SimpleDelta {
/** type alias Aux adds as a type parameter the return Type.
* It is convenient in order to constrain it
* by passing it as a type parameter.
*/
type Aux[I <: HList, O <: HList] = SimpleDelta[I]{ type Out = O }
//Recursive Algorithm
implicit def hnilDelta: Aux[HNil, HNil] = new SimpleDelta[HNil] {
type Out = HNil
def apply(l: HNil, r: HNil): Out = HNil
}
implicit def hconsDelta[H, T <: HList, DT <: HList]
(implicit tailDelta: Aux[T, DT]) : Aux[H::T, Diff[H] :: DT] =
new SimpleDelta[H :: T]{
type Out = Diff[H] :: DT
def apply(l: H :: T, r: H :: T) : Out =
Diff(l.head, r.head) :: tailDelta(l.tail, r.tail)
}
def apply[A, R <: HList](l: A, r: A)
(implicit genA: Generic.Aux[A, R],
delta: SimpleDelta[R]): delta.Out =
delta(genA.to(l), genA.to(r))
}
On this line here
def apply(l: H :: T, r: H :: T) : Out =
Diff(l.head, r.head) :: tailDelta(l.tail, r.tail)
I receive the error "type mismatch". Where the Required type is "Out" and Found type is Diff[H]::DT.
The type that is specified directly above this line is that type Out = Diff[H] :: DT. Not sure why this doesn't work

Merging HList elements

I have a simple service definition
trait Service[-Req, +Rep] extends (Req => Future[Rep]) {
def apply(request: Req): Future[Rep]
}
and a method how to chain services:
implicit class ServiceOps1[Req, RepIn](service: Service[Req, RepIn]) {
def -->[RepOut](next: Service[RepIn, RepOut]): Service[Req, RepOut] =
(req: Req) => service(req) flatMap next
}
I would like to put all my service (in assumption that they could be composed) into HList and then build from HList a composition of service.
Here is my Resolver
trait Resolver[L <: HList, In] {
type Out
def apply(l: L): Service[In, Out]
}
object Resolver {
def apply[L <: HList, In](implicit resolver: Resolver[L, In]): Aux[L, In, resolver.Out] = resolver
type Aux[L <: HList, In, Out0] = Resolver[L, In] { type Out = Out0 }
implicit def hsingleResolver[I, O, S <: Service[I, O]]: Aux[S :: HNil, I, O] =
new Resolver[S :: HNil, I] {
type Out = O
def apply(l : S :: HNil): Service[I, Out] = l.head
}
implicit def hlistResolver[I, O, S <: Service[I, O], T <: HList](implicit res : Resolver[T, O]): Aux[S :: T, I, res.Out] =
new Resolver[S :: T, I] {
type Out = res.Out
def apply(l: S :: T): Service[I, res.Out] = l.head --> res(l.tail)
}
}
I have a service
object S extends Service[Int, String] {
def apply(request: Int): Future[String] = Future successful request.toString
}
When I try to resolve the simple chain
implicitly[Resolver[S.type :: HNil, Int]].apply(S :: HNil)
I got an implicit not found error.
The problem lies in the type signature of your implicits: implicit def hsingleResolver[I, O, S <: Service[I, O]]: Aux[S :: HNil, I, O]. Here because of S <: Service[I, O] you expect O to be inferred based on the type of S, but unfortunately that's not how it works. The S <: Service[I, O] clause in the type parameter list is not taken into consideration for inferring the type arguments. What happens when you invoke implicitly[Resolver[S.type :: HNil, Int]] is that the compiler sees that S = S.type, I = Int and O is unknown so O = Nothing. Then afterwards it goes on to check that S <: Service[Int,Nothing] which is false and implicit search fails.
So to fix this you have to make the fact that S <: Service[I, O] part of the implicit search/type inference process. For instance in one of these ways:
implicit def hsingleResolver[I, O, S](implicit ev: S <:< Service[I,O]): Aux[S :: HNil, I, O] // option 1
implicit def hsingleResolver[I, O, S]: Aux[(S with Service[I,O]) :: HNil, I, O] // option 2
As a side note: wouldn't it make more sense to define Resolver in the following way?
trait Resolver[L <: HList] {
type In
type Out
def apply(l: L): Service[In, Out]
}
object Resolver {
def apply[L <: HList](implicit resolver: Resolver[L]): Aux[L, resolver.In, resolver.Out] = resolver
type Aux[L <: HList, In0, Out0] = Resolver[L] { type In = In0; type Out = Out0 }
...
}
Because In is also dependent on L, just like Out.
Not sure why this was down voted, maybe you could have made a sample repo available. Anyway, here's a partial answer, maybe this get's you back on track.
1) enable debug options for implicits in your build.sbt: scalacOptions += "-Xlog-implicits"
2) define a resolver for HNil: implicit def hNilResolver[I]: Aux[HNil, I, HNil] = ???
3) following the debug output, fix the remainder :)

Writing a typeclass with selection dependent on context bound

My initial code:
sealed trait Adder[L <: HList, U] extends DepFn2[L, Vector[U]]
object Adder {
def apply[L <: HList, U: Ordering](implicit adder: Adder[L, U]): Aux[L, U, adder.Out] = adder
type Aux[L <: HList, U, Out0] = Adder[L, U] { type Out = Out0 }
implicit def found[T <: HList, U: Ordering]: Aux[Vector[U] :: T, U, Vector[U] :: T] =
new Adder[Vector[U] :: T, U] {
type Out = Vector[U] :: T
def apply(l: Vector[U] :: T, collection: Vector[U]): Out = {
(l.head ++ collection).sorted :: l.tail
}
}
implicit def notFound[H, T <: HList, U: Ordering, OutT <: HList](implicit ut: Aux[T, U, OutT]): Aux[H :: T, U, H :: OutT] =
new Adder[H :: T, U] {
type Out = H :: OutT
def apply(l: H :: T, collection: Vector[U]): Out = {
val outT = ut(l.tail, collection)
l.head :: outT
}
}
implicit def empty[U: Ordering]: Aux[HNil, U, Vector[U] :: HNil] =
new Adder[HNil, U] {
type Out = Vector[U] :: HNil
def apply(l: HNil, collection: Vector[U]): Out = collection :: HNil
}
}
I found a bug where things that don't have the context bound
Ordering, the type is passed via notFound instead of found,
which is in hinsight not suprising. I tried to fix the bug by adding
another implicit which should trigger when there is no Ordering:
implicit def foundNoOrdering[T <: HList, U]: Aux[Vector[U] :: T, U, Vector[U] :: T] =
new Adder[Vector[U] :: T, U] {
type Out = Vector[U] :: T
def apply(l: Vector[U] :: T, collection: Vector[U]): Out = {
l.head ++ collection :: l.tail
}
}
However, this results in an ambiguous implicit between the
foundNoOrdering and found. How can I have different code paths
dependent on if there is an Ordering or not?
The standard trick is to reduce the priority by putting the implicit in an ancestor trait
object Adder extends LowPriorityAdderImplicits {
implicit def found...
}
trait LowPriorityAdderImplicits {
implicit def foundNoOrdering....
}
You will find a few of those in the standard library. LowPriorityImplicits seems to be customary in the name.
In the specification:
SLS §7.2 Implicit parameters
If there are several eligible arguments which match the implicit
parameter’s type, a most specific one will be chosen using the rules
of static overloading resolution (§6.26.3)
SLS §6.26.3 : The relevant bit is too long to cite in full, but you have something about
A class or object C is derived from a class or object D if one of the
following holds:
• C is a subclass of D, or
• C is a companion object of a class derived from D, or
• D is a companion object of a class from which C is derived.
and there being derived making it more specific and getting priority in resolution. I believe that one was made just for implicit.

Do a covariant filter on an HList

I intend to filter on an HList in a covariant manner - I would like to include subclasses as well. So the covariant filter on Foo should capture elements of Foo as well as Bar. I've constructed this example trying out <:!<, to see if it does what I would like it to do.
http://scastie.org/6465
/***
scalaVersion := "2.11.2"
libraryDependencies ++= Seq(
"com.chuusai" %% "shapeless" % "2.0.0"
)
*/
import shapeless._
final class HListOps[L <: HList](l: L) {
trait CoFilter[L <: HList, U] extends DepFn1[L] { type Out <: HList }
object CoFilter {
def apply[L <: HList, U](implicit filter: CoFilter[L, U]): Aux[L, U, filter.Out] = filter
type Aux[L <: HList, U, Out0 <: HList] = CoFilter[L, U] { type Out = Out0 }
implicit def hlistCoFilterHNil[L <: HList, U]: Aux[HNil, U, HNil] =
new CoFilter[HNil, U] {
type Out = HNil
def apply(l: HNil): Out = HNil
}
implicit def hlistCoFilter1[L <: HList, H](implicit f: CoFilter[L, H]): Aux[H :: L, H, H :: f.Out] =
new CoFilter[H :: L, H] {
type Out = H :: f.Out
def apply(l: H :: L): Out = l.head :: f(l.tail)
}
implicit def hlistCoFilter2[H, L <: HList, U](implicit f: CoFilter[L, U], e: U <:!< H): Aux[H :: L, U, f.Out] =
new CoFilter[H :: L, U] {
type Out = f.Out
def apply(l: H :: L): Out = f(l.tail)
}
}
def covariantFilter[U](implicit filter: CoFilter[L, U]): filter.Out = filter(l)
}
object Main extends App {
class Foo(val foo: Int)
class Bar(val bar: Int) extends Foo(bar)
val l = new Foo(1) :: new Bar(2) :: new Foo(3) :: new Bar(4) :: HNil
implicit def hlistOps[L <: HList](l: L): HListOps[L] = new HListOps(l)
print(l.covariantFilter[Bar] != l)
}
Gives me
[error] /tmp/rendererbI8Iwy0InO/src/main/scala/test.scala:47: could not find implicit value for parameter filter: _1.CoFilter[shapeless.::[Main.Foo,shapeless.::[Main.Bar,shapeless.::[Main.Foo,shapeless.::[Main.Bar,shapeless.HNil]]]],Main.Bar]
[error] print(l.covariantFilter[Bar] != l)
There are a couple of issues here. The first is that your type class is defined inside of your extension class, but you need the instance at the point where you're calling covariantFilter. Maybe the compiler could find it for you, but it doesn't. It's a lot cleaner not to nest the type class anyway, though.
The second issue is that your two hlistCoFilterN cases don't actually capture all the stuff you want. You only tell the compiler what to do in cases where the type of the head is the filter type and where the filter type is not a subtype of the type of the head. What about where the type of the head is a subtype of the filter type? You probably want something like this:
import shapeless._
trait CoFilter[L <: HList, U] extends DepFn1[L] { type Out <: HList }
object CoFilter {
def apply[L <: HList, U](implicit f: CoFilter[L, U]): Aux[L, U, f.Out] = f
type Aux[L <: HList, U, Out0 <: HList] = CoFilter[L, U] { type Out = Out0 }
implicit def hlistCoFilterHNil[L <: HList, U]: Aux[HNil, U, HNil] =
new CoFilter[HNil, U] {
type Out = HNil
def apply(l: HNil): Out = HNil
}
implicit def hlistCoFilter1[U, H <: U, T <: HList]
(implicit f: CoFilter[T, U]): Aux[H :: T, U, H :: f.Out] =
new CoFilter[H :: T, U] {
type Out = H :: f.Out
def apply(l: H :: T): Out = l.head :: f(l.tail)
}
implicit def hlistCoFilter2[U, H, T <: HList]
(implicit f: CoFilter[T, U], e: H <:!< U): Aux[H :: T, U, f.Out] =
new CoFilter[H :: T, U] {
type Out = f.Out
def apply(l: H :: T): Out = f(l.tail)
}
}
implicit final class HListOps[L <: HList](val l: L) {
def covariantFilter[U](implicit filter: CoFilter[L, U]): filter.Out = filter(l)
}
(For the record, you could also remove the H <:!< U constraint and move hlistCoFilter2 to a LowPriorityCoFilter trait. I find this version a little clearer about its intent, but getting rid of the constraint would arguably be cleaner.)
Now if you have the following:
class Foo(val foo: Int)
class Bar(val bar: Int) extends Foo(bar)
val l = new Foo(1) :: new Bar(2) :: new Foo(3) :: new Bar(4) :: HNil
Your filter will work like this:
scala> l.covariantFilter[Foo] == l
res0: Boolean = true
scala> l.covariantFilter[Bar] == l
res1: Boolean = false
Which I think is what you want.