Skip to content

Instantly share code, notes, and snippets.

@mebubo
Last active August 5, 2019 22:13
Show Gist options
  • Save mebubo/8fe19cbf5f7218003d5d0f32b8b7ca9f to your computer and use it in GitHub Desktop.
Save mebubo/8fe19cbf5f7218003d5d0f32b8b7ca9f to your computer and use it in GitHub Desktop.
/*
* Copyright (c) 2011-18 Miles Sabin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package s2
import shapeless.{Generic, HNil, HList, ::, Unpack1, Lazy, Poly1, Poly}
import shapeless.poly.Case1
trait DataT[F, T] extends Serializable {
def gmapT(t: T): T
}
trait DataT0 {
implicit def dfltDataT[F, T]: DataT[F, T] = DataT(identity)
}
trait DataT1 extends DataT0 {
implicit def deriveInstance[P, F, G](
implicit gen: Generic.Aux[F, G],
dtg: Lazy[DataT[P, G]]
): DataT[P, F] = DataT(t => gen.from(dtg.value.gmapT(gen.to(t))))
}
object DataT extends DataT1 {
def apply[F, T](f: T => T) = new DataT[F, T] {
def gmapT(t: T) = f(t)
}
implicit def deriveHCons[P, H, T <: HList](
implicit ch: Lazy[Case1.Aux[P, H, H]],
dtt: Lazy[DataT[P, T]]
): DataT[P, H :: T] =
DataT(t => ch.value(t.head :: HNil) :: dtt.value.gmapT(t.tail))
}
class EverywhereAux[F] extends Poly
object EverywhereAux {
implicit def default[E, F <: Poly, T, V](
implicit
unpack: Unpack1[E, EverywhereAux, F],
data: Lazy[DataT[E, T]],
f: Case1.Aux[F, T, V] = Case1[F, T, T](identity)
): Case1.Aux[E, T, V] = Case1[E, T, V](t => f(data.value.gmapT(t)))
def everywhere(f: Poly): EverywhereAux[f.type] {} = new EverywhereAux[f.type]
}
object Example {
case class A(a: String, b: Boolean, c: Int)
case class B(a: A, b: Int, c: Boolean)
object f extends Poly1 {
implicit def i = at[Int] {
case x => x + 1
}
implicit def b = at[Boolean] {
case x => !x
}
}
def main(args: Array[String]): Unit = {
val b = B(A("a", true, 1), 2, false)
val b2 = EverywhereAux.everywhere(f)(b)
println(b2)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment