Last active
October 19, 2015 17:56
-
-
Save guersam/da7accb77044d4899030 to your computer and use it in GitHub Desktop.
Generic update without `.copy`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed trait Character | |
case class Player(hp: Int) extends Character | |
case class Civilian(name: String, hp: Int) extends Character | |
case class Monster(hp: Int, weakness: String) extends Character | |
object HittableDemo extends App { | |
import Hittable.ops._ | |
val c1: Character = Player(1) | |
assert(c1.hit == Player(0)) | |
val c2 = Civilian("John", 3) | |
assert(c2.hit == Civilian("John", 1)) | |
assert((c2: Civilian).hit == Civilian("John", 1)) | |
val c3: Character = Monster(2, "Fire") | |
assert(c3.hit == Monster(1, "Fire")) | |
assert(Civilian("John", 3).hit.name == "John") | |
assert(Monster(2, "Fire").hit.weakness == "Fire") | |
} | |
trait Hittable[T] { | |
def apply(t: T): T | |
} | |
object Hittable { | |
object ops { | |
implicit class HitOps[T: Hittable](t: T) { | |
def hit: T = implicitly[Hittable[T]] apply t | |
} | |
} | |
// 'Override' default behavior by providing more specific instance | |
implicit val civilianInstance: Hittable[Civilian] = | |
new Hittable[Civilian] { | |
def apply(c: Civilian): Civilian = c.copy(hp = c.hp - 2) | |
} | |
// Default instances derivation | |
def defaultHitFunc(hp: Int) = hp - 1 | |
import shapeless._ | |
import shapeless.ops.record._ | |
private val wHp = Witness('hp) | |
implicit def genProdHittable[T, Repr <: HList] | |
(implicit | |
prod: HasProductGeneric[T], | |
gen: LabelledGeneric.Aux[T, Repr], | |
modifier: Modifier.Aux[Repr, wHp.T, Int, Int, Repr] | |
): Hittable[T] = | |
new Hittable[T] { | |
def apply(t: T): T = gen.from(modifier(gen.to(t), defaultHitFunc)) | |
} | |
implicit def cnilHittable: Hittable[CNil] = | |
new Hittable[CNil] { | |
def apply(t: CNil): CNil = t | |
} | |
implicit def cconsHittable[H, T <: Coproduct, F, A] | |
(implicit | |
uh: Lazy[Hittable[H]], | |
ut: Lazy[Hittable[T]] | |
): Hittable[H :+: T] = | |
new Hittable[H :+: T] { | |
def apply(t: H :+: T): H :+: T = t match { | |
case Inl(h) => Inl(uh.value(h)) | |
case Inr(t) => Inr(ut.value(t)) | |
} | |
} | |
implicit def genCoprodHittable[T, Repr <: Coproduct] | |
(implicit | |
coprod: HasCoproductGeneric[T], | |
gen: Generic.Aux[T, Repr], | |
hittable: Lazy[Hittable[Repr]] | |
): Hittable[T] = | |
new Hittable[T] { | |
def apply(t: T): T = gen.from(hittable.value(gen.to(t))) | |
} | |
} |
Removed ModifyRepr
and allow overriding default behavior, even if the base type is given in compile time
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Now uses
Modifier
so thattrait Character
doesn't even needdef hp
in itself