Suppose I have a trait like so:
trait A {
def x: Long
def y: Long
}
And I have a class which takes an A and needs to be an A:
case class B(a: A, foo: Foo, bar: Bar) extends A {
override def x = a.x
override def y = a.y
}
If A had lots of members, this would get annoying quickly. Is there a pattern that lets me "decorate" A with a foo and a bar?
I came up with such code, i don't know if it would be of any use for you:
object SelfAnnotationExample extends App{
trait A {
def x: Lon
def y: Long
}
trait ExtendedA extends A { self: InstanceProvider[A] =>
def x: Long = self.instance.x
def y: Long = self.instance.y
}
trait InstanceProvider[A] {
def instance: A
}
case class B(instance: A, foo: Any) extends ExtendedA with InstanceProvider[A]
case class TestA(x: Long, y: Long) extends A
val test = B(TestA(3, 4), 23)
println(test.x)
println(test.y)
}
I use scala feature known as "self type" (Someone correct me if i named it wrong). Trait InstanceProvider is not limited for this particular case. This solution need additional trait ExtendedA definition but every concrete implementation of A can utilize it.
If you want to call members from A on B and want to pass the A part of B to functions expecting A, you can achieve it using implicit conversion from B to A:
import scala.language.implicitConversions
object Main extends App{
trait A {
def x: Long
def y: Long
}
def processA(a: A) = ()
class Foo
class Bar
case class B(a: A, foo: Foo, bar: Bar)
implicit def bToA(b: B): A = b.a
case class TestA(x: Long, y: Long) extends A
val test = B(TestA(3, 4), new Foo, new Bar)
println(test.x)
println(test.y)
processA(test)
}
Related
I have an implicit class that needs to use a given parameter at runtime. So I define this implicit in another class that takes this parameter in the constructor. A simplified version of what I am doing is as follows:
case class A(p1: String) {
def foo = println("foo: " + p1)
}
class B(p2: String) {
implicit class Enhancer(a: A) {
implicit def bar = s"bar: ${a.p1}, $p2"
}
}
So when I need to use this class I then do the following:
val a = A("x")
val b = new B("y")
import b._
a.bar
I am wondering if there is a neater way than the above? Specifically the middle two lines where I define the object and then import from it. For example is there any way I could have a one line call to return the implicit class I need?
Try to add implicit parameter to Enhancer.
case class A(p1: String) {
def foo = println("foo: " + p1)
}
class B(val p2: String)
implicit class Enhancer(a: A)(implicit b: B) {
implicit def bar = s"bar: ${a.p1}, ${b.p2}"
}
val a = A("x")
implicit object b extends B("y")
a.bar
or
implicit val b = new B("y")
a.bar
Or
implicit class Enhancer(val a: A) extends AnyVal {
implicit def bar(implicit b: B) = s"bar: ${a.p1}, ${b.p2}"
}
I'm trying to make a typeclass that depends on user input. Imagine we have some case objects:
sealed trait H
case object Ha extends H
case object Hb extends H
and the type class:
trait Foo[A] {
def bar: String
}
object Foo {
def bar[A : Foo] = implicitly[Foo[A]].bar
implicit object FooA extends Foo[Ha.type] {
override def bar: String = "A"
}
implicit object FooB extends Foo[Hb.type] {
override def bar: String = "B"
}
}
While I found a working solution using a match:
variableComingFromMainArgs match {
case "a" => Foo.bar[Ha.type] _
case "b" => Foo.bar[Hb.type] _
}
I remember that we have abstract types in Scala, so I could change my case class into:
sealed trait H {
type T <: H
}
case object Ha extends H {
type T = this.type
}
case object Hb extends H {
type T = this.type
}
Now, when depending on user input to the program, I could do something like
val variable = Ha
println(Foo.bar[variable.T])
However, for some reason this doesn't work the and the error is not very useful for me:
error: could not find implicit value for evidence parameter of type Foo[variable.T]
println(Foo.bar[variable.T])
Any ideas if this can be overcome, if not, why?
Thanks.
Implicits are compile time constructs so in principle they cannot depend on user input directly (programmer can wire it for example with pattern matching as you did).
Consider the following code. It compiles and works as intended:
trait H {
type A
}
case object Ha extends H {
override type A = Int
}
case object Hb extends H {
override type A = Long
}
trait Adder[T] {
def add(a: T, b: T): T
}
implicit object IntAdder extends Adder[Int] {
override def add(a: Int, b: Int): Int = a + b
}
implicit object LongAdder extends Adder[Long] {
override def add(a: Long, b: Long): Long = a + b
}
def addWithAdder(input: H)(a: input.A, b: input.A)(implicit ev: Adder[input.A]): input.A = ev.add(a, b)
val x: Int = addWithAdder(Ha)(3, 4)
val y: Long = addWithAdder(Hb)(3, 4)
Let's focus on addWithAdder method. Thanks to path dependent types compiler can choose correct implicit for this task. But still this method is basically the same as the following:
def add[T](a: T, b: T)(implicit ev: Adder[T]) = ev.add(a, b)
The only advantage first one can have is that you can provide all instances yourself and stop the user of your code to add own types (when H is sealed and all implementations are final).
Let's say I have the following code for value classes:
class Meters(val x: Int) extends AnyVal {
def +(m: Meters): Meters = new Meters(x + m.x)
}
class Seconds(val x: Int) extends AnyVal {
def +(s: Seconds): Seconds = new Seconds(x + s.x)
}
Is there any way for me to remove duplication of the "+" methods?
Something kind of like:
abstract class Units[T <: Units[T]](val x: Int) extends AnyVal {
def +(other: T): T = T(x + other.x)
}
Except I can't inherit from value classes, and I definitely can't use T like a constructor.
You can use a universal trait with a type class, lets start defining the trait.
trait Sum[T <: Sum[T]] extends Any {
val x: Int
def +(other: T)(implicit evidence : FromInt[T]): T = evidence.fromInt(x + other.x)
}
Now we need a type class that tell us how to go from an integer to some type, lets define this and call it FromInt
trait FromInt[T] {
def fromInt(x: Int) : T
}
now lets define the Meters value class which is as simple as
class Meters(val x :Int) extends AnyVal with Sum[Meters]
and in the companion object we can provide an implicit value of the type class we defined.
object Meters{
implicit val intConstructable : FromInt[Meters] = new FromInt[Meters] {
override def fromInt(x: Int) = new Meters(x)
}
}
and now we can just do
val added = new Meters(2) + new Meters(3)
println(added.x)
Hi so I have this use case where I have a function which takes a type which extends a trait. Let's say the trait a is:
trait A {
val a: Double
}
Now I have multiple case classes that extend a.
case class B(val a: Double) extends A
case class C(val a: Double, val b: Double) extends A
Now I want a generalized funtion such as:
def change[T <: A](newA: Double, state: T): T = {
state.copy(a = newA)
}
If I can some how specify that the generic T is a case class that extends A, I can than infer that state has a clone method that has a param a. Or maybe there is a way to define a generic that says that there is a clone function that has exactly one param that is a.
Thanks
Building on a comment by cchantep, and on a similar question I have asked recently, following works:
trait A[T <: A[T]] {
val a: Double
def clone(a: Double = a): T
}
case class B(a: Double) extends A[B] {
def clone(a: Double = a) = copy(a = a)
}
case class C(a: Double, b: Double) extends A[C] {
def clone(a: Double = a) = copy(a = a)
}
def change[T <: A[T]](newA: Double, state: T): T = {
state.clone(a = newA)
}
Is there any reason why do you want change to return the specific type and not just A? Without this requirement is could be a lot simpler, I have added the recursive type only to meet this requirement (to describe clone is always returning the original type):
trait A {
val a: Double
def clone(a: Double = a): A
}
case class B(a: Double) extends A {
def clone(a: Double = a) = copy(a = a)
}
case class C(a: Double, b: Double) extends A {
def clone(a: Double = a) = copy(a = a)
}
def change(newA: Double, state: A): A = {
state.clone(a = newA)
}
Even with this simple implementation you could use clone directly instead of change and it would still keep the derived type statically. Still, I think such requirement makes little sense, and in the situations you compiler knows it is B or C, not A, you can use copy directly, you need change only when you have A only.
if I have an ADT and a type class, is there a way for me to ensure at compile time that there is an instance of the type class for every subtype of the ADT?
Just to give an example - I'd really like this to not compile as there isn't an instance of A for Baz
sealed trait Foo
final case class Bar(s: String) extends Foo
final case class Baz(i: Int) extends Foo
trait A[T <: Foo] {
type O
def f(t: T): O
}
implicit val barA = new A[Bar] {
type O = String
def f(t: Bar): O = t.s
}
This is all my own code, so I'm happy to change the encoding of Foo if required (maybe a shapeless coproduct can help me out here?)
EDIT
Sorry, should have mentioned - I have a function a bit like this I'd like to implement (lets assume my instances are in an object I've imported and they are the only implementations in scope)
def g[T <: Foo](fs: List[T])(implicit a: A[T]): List[a.O] = fs.map(a.f(_))
From the comments below, it looks like I should also have said that the thing that calls g can do so with a List of any subclass of Foo (I have no control over that part other than to change g I guess). Here, I'm trying to ensure that if someone changes Foo later on, then there will be a compiler error letting the user know that they need to implement an appropriate A
You can use F-bounded polymorphism (aka Curiously Recurrent Template Pattern):
sealed abstract class Foo[Self <: Foo](implicit val hasA: A[Self])
final case class Bar(s: String) extends Foo[Bar]
final case class Baz(i: Int) extends Foo[Baz]
abstract class is used instead of trait so the implicit is picked up automatically.
However, for this specific A and g, you may not really need a type class:
sealed trait Foo[O] {
def f(): O
}
final case class Bar(s: String) extends Foo[String] {
def f() = s
}
def g(fs: List[Foo[O]]): List[O] = fs.map(_.f())
trait Foo[T] {
this: ImplementThis[T] =>
}
case class Bar() extends Foo[String] with ImplementThis[String] {
override def f(t: String): String = {
t
}
}
case class Baz() extends Foo[Int] with ImplementThis[Int] {
override def f(t: Int): Int = {
t
}
}
trait ImplementThis[T] {
type O
def f(t: T): O
}
Try something like this. This will enforce implementation of def f(t: T):O for any subclass of Foo that's defined.
def g[T <: Foo](fs: List[T])(implicit a: A[T]): List[a.O] = fs.map(a.f(_))
From this, I assume you want all the child classes of your Foo to have a def f so that they dont fail at runtime. I think my above suggestion will enforce that def f implementation and solve this problem.