Scala shapeless zip issue - scala

In the example below, I get could not find implicit value for parameter zipper: shapeless.ops.hlist.Zip[shapeless.::[keys.Out,shapeless.::[mapper.Out,shapeless.HNil]]]
I presume I need another implicit, but can't work out the syntax. Ideas?
def mapCCLV[P <: Product, K <: HList, L <: HList, M <: HList](p: P)(poly: Poly1)(
implicit gen: Generic.Aux[P, L], lab: LabelledGeneric.Aux[P, K],
keys: Keys[K], mapper: Mapper.Aux[poly.type, L, M]) = {
val k = keys.apply
val v = gen.to(p).map(poly)
k.zip(v)
}

Like the error message says, you need an extra implicit parameter for a Zip type class instance, to be able to zip.
import shapeless._, shapeless.ops.hlist._, record._, ops.record._, labelled._
def mapCCLV[P <: Product, LG <: HList, K <: HList, G <: HList, M <: HList](
p: P)(poly: Poly1
)(implicit
gen: Generic.Aux[P, G],
lab: LabelledGeneric.Aux[P, LG],
keys: Keys.Aux[LG, K],
mapper: Mapper.Aux[poly.type, G, M],
zip: Zip[K :: M :: HNil]
): zip.Out = {
val k = keys()
val v = gen.to(p).map(poly)
k.zip(v)
}
More likely you want to use ZipWithKeys instead of Zip.
def mapCCLV[P <: Product, LG <: HList, K <: HList, G <: HList, M <: HList, Out <: HList](
p: P)(poly: Poly1
)(implicit
gen: Generic.Aux[P, G],
lab: LabelledGeneric.Aux[P, LG],
keys: Keys.Aux[LG, K],
mapper: Mapper.Aux[poly.type, G, M],
zwk: ZipWithKeys.Aux[K, M, Out]
) = gen.to(p).map(poly).zipWithKeys(keys())

Related

Shapeless. How filter LabelledGeneric record by keys?

I have the next piece of code which I want to use for type class instances creation:
def productsLogShow[HK <: HList, T, H <: HList, K](hideFieldsWithKeys: HK)(
implicit lg: LabelledGeneric.Aux[T, H], lsh: LogShow[H], keys: Keys.Aux[H, K]
): LogShow[T] = {
LogShow.create { value =>
val record = lg.to(value)
// ...
//filter somehow record and get a record without
// keys which are in 'hideFieldsWithKeys'
// ...
}
}
So, how can I filter record and do I use the correct type for hideFieldsWithKeys parameter?
UPDATED:
Full code snippet that should work according to Dmitro's answer
object Main extends App {
trait LogShow[T] {
def show(value: T): String
}
object LogShow {
def apply[T: LogShow]: LogShow[T] = implicitly[LogShow[T]]
def create[T](f: T => String): LogShow[T] = new LogShow[T] {
override def show(value: T): String = f(value)
}
}
import LogShow.create
implicit val StringShow: LogShow[String] = create(identity)
import shapeless._
import shapeless.labelled.FieldType
import shapeless.ops.hlist.LeftFolder
import shapeless.ops.record.Remover
import scala.reflect.ClassTag
def productsLogShow[HK <: HList, T, H <: HList, H1 <: HList, K <: HList](hideFieldsWithKeys: HK)
(implicit
ct: ClassTag[T],
lg: LabelledGeneric.Aux[T, H],
rem: RemoverAll.Aux[H, HK, H1],
lsh: LogShow[H1]): LogShow[T] = {
LogShow.create { value =>
val record = lg.to(value)
val clearedRecord = rem(record, hideFieldsWithKeys)
s"${ct.runtimeClass.getSimpleName}:\n${lsh.show(clearedRecord)}"
}
}
trait RemoverAll[L <: HList, K <: HList] extends DepFn2[L, K]
object RemoverAll {
type Aux[L <: HList, K <: HList, Out0 <: HList] = RemoverAll[L, K] {type Out = Out0}
def create[L <: HList, K <: HList, Out0 <: HList](f: (L, K) => Out0): Aux[L, K, Out0] = new RemoverAll[L, K] {
override type Out = Out0
override def apply(l: L, k: K): Out0 = f(l, k)
}
implicit def mk[K <: HList, L <: HList, Out <: HList](implicit leftFolder: LeftFolder.Aux[K, L, removeKeys.type, Out]): Aux[L, K, Out] =
create((l, k) => leftFolder(k, l))
object removeKeys extends Poly2 {
implicit def cse[K, L <: HList, V, Out <: HList](implicit remover: Remover.Aux[L, K, (V, Out)]): Case.Aux[L, K, Out] =
at((l, _) => remover(l)._2)
}
}
implicit def hconsLogShow[K <: Symbol, H, T <: HList](implicit
wt: Witness.Aux[K],
lshHead: LogShow[H],
lshTail: LogShow[T]): LogShow[FieldType[K, H] :: T] =
LogShow.create { value =>
s"${wt.value.name}: ${lshHead.show(value.head)}\n${lshTail.show(value.tail)}"
}
implicit val hnilLogShow: LogShow[HNil] = LogShow.create(_ => "")
//test
case class Address(country: String, street: String)
implicit val inst: LogShow[Address] = productsLogShow('country :: HNil)
//could not find implicit value for parameter lg: shapeless.LabelledGeneric.Aux[T,H]
//[error] implicit val inst: LogShow[Address] = productsLogShow('country :: HNil)
println(implicitly[LogShow[Address]].show(Address("Ukraine", "Gorkogo")))
}
Try
import shapeless.ops.hlist.LeftFolder
import shapeless.ops.record.{Keys, Remover}
import shapeless.{::, DepFn2, HList, HNil, LabelledGeneric, Poly2, Witness}
import shapeless.record.Record
def productsLogShow[HK <: HList, T, H <: HList, H1 <: HList, K <: HList](hideFieldsWithKeys: HK)(
implicit lg: LabelledGeneric.Aux[T, H], lsh: LogShow[H], /*keys: Keys.Aux[H, K]*/ rem: RemoverAll.Aux[H, HK, H1]
): LogShow[T] = {
LogShow.create { value =>
val record = lg.to(value)
val record1 = rem(record, hideFieldsWithKeys)
???
}
}
trait RemoverAll[L <: HList, K <: HList] extends DepFn2[L, K]
object RemoverAll {
type Aux[L <: HList, K <: HList, Out0 <: HList] = RemoverAll[L, K] { type Out = Out0 }
def create[L <: HList, K <: HList, Out0 <: HList](f: (L, K) => Out0): Aux[L, K, Out0] = new RemoverAll[L, K] {
override type Out = Out0
override def apply(l: L, k: K): Out0 = f(l, k)
}
implicit def mk[K <: HList, L <: HList, Out <: HList](implicit leftFolder: LeftFolder.Aux[K, L, removeKeys.type, Out]): Aux[L, K, Out] =
create((l, k) => leftFolder(k, l))
object removeKeys extends Poly2 {
implicit def cse[K, L <: HList, V, Out <: HList](implicit remover: Remover.Aux[L, K, (V, Out)]): Case.Aux[L, K, Out] =
at((l, _) => remover(l)._2)
}
}
implicitly[RemoverAll.Aux[Record.`'i -> Int, 's -> String, 'b -> Boolean`.T, Witness.`'s`.T :: Witness.`'i`.T :: HNil, Record.`'b -> Boolean`.T]]
Replace the line
implicit val inst: LogShow[Address] = productsLogShow('country :: HNil)
with
import shapeless.syntax.singleton._
implicit val inst: LogShow[Address] = productsLogShow('country.narrow :: HNil)
'country had type Symbol instead of necessary singleton type Witness.`'country`.T.

Witness type derivation issue

I want to build general solution for field removing from case classes.
Using this trick I built this working code:
implicit class SemiGenericIgnoringOps[T](t: T) {
def ignoring[TRepr <: HList,
V,
TargetRepr <: HList,
H <: HList](k: Witness)
(implicit
gen: LabelledGeneric.Aux[T, TRepr],
rem: Remover.Aux[TRepr, k.T, (V, TargetRepr)],
upd: Updater.Aux[TargetRepr, FieldType[k.T, V], H],
ali: Align[H, TRepr]
): SemiGeneric.Aux[T, TargetRepr] = new SemiGeneric[T] {
type Repr = TargetRepr
def convert: TargetRepr = gen.to(t) - k
}
}
I want to replace single k: Witness with HList of Witnesss. But even adding a generic Witness type parameter cause the compilation error: can't find implicit value for Remover.
implicit class SemiGenericIgnoringOps[T](t: T) {
def ignoring[TRepr <: HList,
V,
TargetRepr <: HList,
H <: HList,
W <: Witness](w: W) // added type parameter
(implicit
gen: LabelledGeneric.Aux[T, TRepr],
rem: Remover.Aux[TRepr, w.T, (V, TargetRepr)],
upd: Updater.Aux[TargetRepr, FieldType[w.T, V], H],
ali: Align[H, TRepr]
): SemiGeneric.Aux[T, TargetRepr] = new SemiGeneric[T] {
type Repr = TargetRepr
def convert: TargetRepr = gen.to(t) - w
}
}
It seems that compilator can't derive Witness.T. Trick with Witness.Aux[R] doesn't help. How to overcome this problem?
On contrary to the answer you referred to, you don't need Updater and Align since your convert works with HList / record.
The following code works:
import shapeless.ops.record.Remover
import shapeless.{::, HList, HNil, LabelledGeneric, Witness}
trait GenericAllKeysRemover[A <: Product, K <: HList] {
type Out <: HList
def apply(a: A): Out
}
object GenericAllKeysRemover {
type Aux[A <: Product, K <: HList, Out0 <: HList] = GenericAllKeysRemover[A, K] { type Out = Out0 }
def instance[A <: Product, K <: HList, Out0 <: HList](f: A => Out0): Aux[A, K, Out0] = new GenericAllKeysRemover[A, K] {
override type Out = Out0
override def apply(a: A): Out = f(a)
}
def apply[A <: Product, K <: HList](implicit genericAllKeysRemover: GenericAllKeysRemover[A, K]): Aux[A, K, genericAllKeysRemover.Out] = genericAllKeysRemover
implicit def mkGenericAllKeysRemover[A <: Product, L <: HList, K <: HList, Out <: HList](implicit
labelledGeneric: LabelledGeneric.Aux[A, L],
allKeysRemover: AllKeysRemover.Aux[L, K, Out]): Aux[A, K, Out] =
instance(a => allKeysRemover(labelledGeneric.to(a)))
}
trait AllKeysRemover[L <: HList, K <: HList] {
type Out <: HList
def apply(l: L): Out
}
object AllKeysRemover {
type Aux[L <: HList, K <: HList, Out0 <: HList] = AllKeysRemover[L, K] { type Out = Out0 }
def instance[L <: HList, K <: HList, Out0 <: HList](f: L => Out0): Aux[L, K, Out0] = new AllKeysRemover[L, K] {
override type Out = Out0
override def apply(l: L): Out0 = f(l)
}
def apply[L <: HList, K <: HList](implicit allKeysRemover: AllKeysRemover[L, K]): Aux[L, K, allKeysRemover.Out] =
allKeysRemover
implicit def mkAllKeysRemover[L <: HList]: Aux[L, HNil, L] = instance(identity)
implicit def mkAllKeysRemover1[L <: HList, H, T <: HList, V, L_removeH <: HList, Out <: HList](implicit
remover: Remover.Aux[L, H, (V, L_removeH)],
allKeysRemover: Aux[L_removeH, T, Out]): Aux[L, H :: T, Out] =
instance(l => allKeysRemover(remover(l)._2))
}
case class MyClass(i: Int, s: String, b: Boolean)
GenericAllKeysRemover[MyClass, Witness.`'s`.T :: Witness.`'b`.T :: HNil].apply(MyClass(1, "a", true)) //1 :: HNil

Shapeless lenses strange behavior

I am trying to convert my case class into a sequence containing a lens for each field. I've created the following simplified example to highlight the problem that I am having.
The following code will give a runtime error:
import shapeless._
case class Testing(field1: String, field2: Double)
val lenses = Seq(0,1).map(i => lens[Testing] >> i)
whereas the following does not:
import shapeless._
case class Testing(field1: String, field2: Double)
val lens1 = lens[Testing] >> 0
val lens2 = lens[Testing] >> 1
val lenses = Seq(lens1, lens2)
The actual error reads "Expression i does not evaluate to a non-negative Int literal".
I feel like this error message is misleading since the code val lens3 = lens[Testing] >> 2 (i.e. accessing one field too many) would give the same error message.
Has anyone experienced behaviour like this in shapeless? And is there an easier way to extract element lenses for each field in my Case Class into a sequence (i.e. not like #lenses in monocle where you still need to access each lens using the field name)?
lens[Testing] >> 0
lens[Testing] >> 1
are implicitly transformed to
lens[Testing] >> Nat._0
lens[Testing] >> Nat._1
and this works but
val lenses = Seq(0,1).map(i => lens[Testing] >> i)
or val lenses = Seq(Nat._0,Nat._1).map(i => lens[Testing] >> i) doesn't.
Seq(Nat._0,Nat._1) has type Seq[Nat], so i has type Nat (rather than specific Nat._0, Nat._1) and this is too rough.
The following approach with constructing HList of lenses (rather than Seq) seems to work:
import shapeless.{::, Generic, HList, HNil, Lens, MkHListSelectLens}
case class Testing(field1: String, field2: Double)
trait MkLensHlist[A] {
type Out <: HList
def apply(): Out
}
object MkLensHlist {
type Aux[A, Out0 <: HList] = MkLensHlist[A] { type Out = Out0 }
def instance[L, Out0 <: HList](x: Out0): Aux[L, Out0] = new MkLensHlist[L] {
override type Out = Out0
override def apply(): Out0 = x
}
def apply[A](implicit instance: MkLensHlist[A]): instance.Out = instance()
implicit def mk[A, L <: HList, Out <: HList](implicit
gen: Generic.Aux[A, L],
apply: ApplyMkHListSelectLens.Aux[L, Out]
): Aux[A, Out] = instance(apply())
}
trait ApplyMkHListSelectLens[L <: HList] {
type Out <: HList
def apply(): Out
}
object ApplyMkHListSelectLens {
type Aux[L <: HList, Out0 <: HList] = ApplyMkHListSelectLens[L] { type Out = Out0}
def instance[L <: HList, Out0 <: HList](x: Out0): Aux[L, Out0] = new ApplyMkHListSelectLens[L] {
override type Out = Out0
override def apply(): Out0 = x
}
implicit def mk[L <: HList, Out <: HList](implicit
apply: ApplyMkHListSelectLens1.Aux[L, L, Out]
): Aux[L, Out] =
instance(apply())
}
trait ApplyMkHListSelectLens1[L <: HList, L1 <: HList] {
type Out <: HList
def apply(): Out
}
object ApplyMkHListSelectLens1 {
type Aux[L <: HList, L1 <: HList, Out0 <: HList] = ApplyMkHListSelectLens1[L, L1] { type Out = Out0}
def instance[L <: HList, L1 <: HList, Out0 <: HList](x: Out0): Aux[L, L1, Out0] = new ApplyMkHListSelectLens1[L, L1] {
override type Out = Out0
override def apply(): Out0 = x
}
implicit def mk1[L <: HList, H, T <: HList, Out <: HList](implicit
lens: MkHListSelectLens[L, H],
apply: Aux[L, T, Out]
): Aux[L, H :: T, Lens[L, H] :: Out] =
instance(lens() :: apply())
implicit def mk2[L <: HList]: Aux[L, HNil, HNil] =
instance(HNil)
}
MkLensHlist[Testing]
// shapeless.MkHListSelectLens$$anon$36$$anon$17#340f438e :: shapeless.MkHListSelectLens$$anon$36$$anon$17#30c7da1e :: HNil

Extract FieldType key and value from HList

I would like to extract the key and value of the head of an HList using these two methods:
def getFieldName[K, V](value: FieldType[K, V])(implicit witness: Witness.Aux[K]): K = witness.value
def getFieldValue[K, V](value: FieldType[K, V]): V = value
I tried a few variations of this function, but I couldn't make it work, I think this might be the closest to the right solution:
def getFieldNameValue[Key <: Symbol, Value <: AnyRef, Y <: HList, A <: Product](a : A)
(implicit
gen : LabelledGeneric.Aux[A, FieldType[Key, Value] :: Y],
witness: shapeless.Witness.Aux[Key]) = {
val aGen = gen.to(a).head
(getFieldName(aGen), getFieldValue(aGen))
}
But it throws this exception:
could not find implicit value for parameter gen: shapeless.LabelledGeneric.Aux[Ex,shapeless.labelled.FieldType[Key,Value] :: Y]
I'd like to call it like this:
scala> case class Ex(i: Int, ii: Int)
scala> val ex = Ex(1,2)
scala> getFieldNameValue(ex)
res1: (String, Int) = (i,1)
This variant works:
def getFieldNameValue[A <: Product, Repr <: HList,
K <: Symbol, V, T <: HList](a: A)(implicit
gen: LabelledGeneric.Aux[A, Repr],
ev: Repr <:< (FieldType[K, V] :: T),
witness: Witness.Aux[K]): (String, V) = {
val record: Repr = gen.to(a)
(witness.value.name, record.head)
}
getFieldNameValue(ex) // (i,1)
I guess the trouble was that you tried to do too much work in one step (implicits don't like that).

How to implement zipWithIndex on HLists

Writting algorithm on HList, I need a zipWithIndex function. It is not at the shapeless library by now, so I decided to implement it.
It is quite obvious that it might be implemented as
hlist.zip(indexes)
where indexes is the HList of the indexes (0..n), that probably could be obtained this way:
val indexes = Nat._0 until hlist.length
Issue here is that Nat doesn't have until method. I haven't found any Witness for the HList index to use with HList.map.
What is the method I could use to obtain HList of Nats starting with Nat._0 till hlist.length?
It might make sense to add something like this to Shapeless:
import shapeless._, ops.hlist.Prepend
trait Range[A <: Nat, B <: Nat] extends DepFn0 { type Out <: HList }
object Range {
type Aux[A <: Nat, B <: Nat, Out0 <: HList] = Range[A, B] { type Out = Out0 }
implicit def emptyRange[A <: Nat]: Aux[A, A, HNil] = new Range[A, A] {
type Out = HNil
def apply(): Out = HNil
}
implicit def slightlyBiggerRange[A <: Nat, B <: Nat, OutAB <: HList](implicit
rangeAB: Aux[A, B, OutAB],
appender: Prepend[OutAB, B :: HNil],
witnessB: Witness.Aux[B]
): Aux[A, Succ[B], appender.Out] = new Range[A, Succ[B]] {
type Out = appender.Out
def apply(): Out = appender(rangeAB(), witnessB.value :: HNil)
}
}
def range[A <: Nat, B <: Nat](implicit r: Range[A, B]): r.Out = r()
Now you can write zipWithIndex pretty cleanly:
import ops.hlist.{ Length, Zip }
def zipWithIndex[L <: HList, S <: Nat, R <: HList, Out <: HList](l: L)(implicit
len: Length.Aux[L, S],
range: Range.Aux[nat._0, S, R],
zipper: Zip.Aux[L :: R :: HNil, Out]
): Out = l.zip(range())
And then:
import nat._
type Expected = (Int, _0) :: (Symbol, _1) :: (String, _2) :: HNil
val xs: Expected = zipWithIndex(1 :: 'a :: "foo" :: HNil)
You could also use a fold or a ZippedWithIndex[L <: HList] type class, both of which might be a little more concise, but less clearly composed out of independently useful pieces like Range.