Imagine that I have the class Imaginary(x) and the class Real(y) in Scala. Is there a way to do ComplexNumber = 3 + 2i instead of doing ComplexNumber = Real(3) + Imaginary(2) ?
Thanks.
Is 3 + 2.i enough?
sealed trait ComplexNumber {
val re: Int
val im: Int
}
case class Real(re: Int) extends ComplexNumber { val im: Int = 0 }
implicit class ToReal(val re: Int) extends AnyVal {
def +(that: Imaginary) = Mixed(re, that.im)
}
case class Imaginary(im: Int) extends ComplexNumber { val re: Int = 0 }
implicit class ToImaginary(val im: Int) extends AnyVal {
def i: Imaginary = Imaginary(im)
}
case class Mixed(re: Int, im: Int) extends ComplexNumber
Usage:
scala> 3 + 2.i
res3: Mixed = Mixed(3,2)
2i means 2*i. You can't replace 2*a with 2a in scala so you should use operator *.
case class ComplexNumber(re: Int, im: Int){
def +(that: ComplexNumber) = ComplexNumber(re + that.re, im + that.im)
def -(that: ComplexNumber) = ComplexNumber(re - that.re, im - that.im)
def *(that: ComplexNumber) = ComplexNumber(re*that.re - im*that.im, re*that.im + im*that.re)
}
implicit def intToComplec(i: Int): ComplexNumber = ComplexNumber(i, 0)
object I extends ComplexNumber(0, 1)
Usage:
scala> 3 + 2*I
res0: ComplexNumber = ComplexNumber(3,2)
scala> 4 - I
res1: ComplexNumber = ComplexNumber(4,-1)
Be careful. Remember that the real and imaginary parts of a complex number have to both be real. Could you do something like:
case class Complex(real: Real, imag: Real) {
// in here define all your arithmetic ops
}
Then you could use senia's implicit trick to turn numbers automatically into reals and declare an i method in Real that would turn it into an imaginary number.
// inside Real
def i: Complex = Complex(Real(0), this)
I would just caution you not to complicate the code too much, just for the sake of cute syntax. Complex(a, b) is nice and clear. If you want to create a parser, feel free, but I'd reserve that for String values and let code be code.
No, this is not possible. The lexical analysis phase of the compiler "owns" suffixes on numeric strings such as f (Float), d (Double) and l (Long) and there is no extensibility for this notation.
You might want to think about using the new string interpolation mechanism to annotate constants. You'd have to accept parsing them and the "flag," if you will (your i), would have to be used in prefix position. That would give you something like this:
val imaginary = i"1.2+3.4i"
I'm not up-to-date with the capabilities of macros in the new compiler, but perhaps you could get the parsing done at compile time, which would preclude attempting to work with malformed values at run-time.
This approach (whether compile-time or run-time parsed) would be flexible (insofar as you can be as accommodating as you like in the accepted formats) but it clearly does not match the notation that people use in mathematical texts.
Related
How can I create multiple types that are essentially Ints, i.e can get the int value, can use math operators like + BUT where instances of different types can not be mixed.
For example:
val density1 = new Density(100)
val density2 = new Density(200)
density1 + density2 should be(new Density(300))
val variability = new Variability(1)
variability.value should be(1)
density1 + variability // does not compile
There could be hundreds of these types and I do not want to have to implement operators like + in each leaf class.
Ideally, I would like to avoid all implicit conversion mechanisms (personal preference only). Additional types should not require altering existing types.
Here's a solution in Scala 3 that I don't think uses boxing/unboxing:
object Wrappers:
opaque type Wrapper = Int
extension[T <: Wrapper](t: T)(using util.NotGiven[T =:= Wrapper]):
def +(other: T): T = (t + other).asInstanceOf[T]
//other methods
opaque type Density <: Wrapper = Int
def Density(i: Int): Density = i
opaque type Variability <: Wrapper = Int
def Variability(i: Int): Variability = i
Try it in Scastie
Testing:
val density1 = Density(1)
val density2 = Density(2)
val density3: Density = density1 + density2 //compiles
val check1: Variability = density1 + density2 //doesn't compile
val variability = Variability(1)
val check2 = (variability: Wrapper) + density2 //doesn't compile
val check3 = variability + density2 //doesn't compile
println(density1) //1
println(density2) //2
println(density3) //3
The asInstanceOf is unchecked and shouldn't affect performance. This design should also keep the Ints from being boxed, but I can't guarantee that, and it also depends on how you use this. Another nice thing about this is that every new type requires only 2 more lines of code. And to make adding new methods easier, you can probably also make a new method of your own to shorten asInstanceOf[T].
trait TaggedInt[T <: TaggedInt[T]] {
val value: Int
protected def apply(value: Int): T
def +(other: T) = apply(value + other.value)
// etc.
}
case class Density(value: Int) extends TaggedInt[Density] {
override protected def apply(value: Int) = Density(value)
}
I was desperately trying to get around having to repeat override protected def apply(value: Int) = ... all the time
You can make it a constructor parameter then. Slightly less efficient but probably won't matter in practice:
abstract class TaggedInt[T <: TaggedInt[T]](constructor: Int => T) {
val value: Int
def +(other: T) = constructor(value + other.value)
// etc.
}
case class Density(value: Int) extends TaggedInt[Density](Density)
I originally had
case class TaggedInt[Tag](value: Int) extends AnyVal {
def +(other: TaggedInt[Tag]) = TaggedInt[Tag](value + other.value)
// etc.
}
trait DensityTag
type Density = TaggedInt[DensityTag]
trait VariabilityTag
type Variability = TaggedInt[VariabilityTag]
but it has at least 2 problems for this usecase:
Density(100).toString is TaggedInt(100) instead of Density(100);
Density(100) is equal to Variability(100).
Let us assume we have a trait T. What is the best way to achieve the following:
Everybody who writes an implementation of T should be forced to provide a possibility that allows a parameter-free initialization of T, i.e., we probably have to enforce the implementation of a configurable factory.
All logic/data that only depends on the actual initialization parameters (of a certain implementation A of T) should be handled/stored centrally, but should be available in both the factory and A.
The most simple/concise way I see to achieve this (approximately) would be to add a trait for a factory and link T to this factory:
trait T {
val factory: TFactory
}
trait TFactory {
def build(): T
val description: String // example for logic/data that only depend on the parameters
}
// example implementation:
class A(val factory: AFactory, paramA: Int, paramB: Int, paramC: Int) extends T
class AFactory(paramA: Int, paramB: Int, paramC: Int) extends TFactory {
def build = new A(this, paramA, paramB, paramC)
val description = f"$paramA $paramB $paramC"
}
Obviously this does not really "enforce" the implementation of a factory (as long as there is an alternative implementation available) and obviously it is possible to generate instantiations of A which link to a "wrong" TFactory. What I also don't like about this approach is the repetition of the initialization parameters. I often create yet another class AParams which again wraps all parameters (for instance to facilitate adding new parameters). Thus, I end up with three classes, which imho is a lot of boilerplate for this simple problem.
My question is whether there is a (maybe completely) different approach, which achieves the same primary goals but is more concise?
I'm not quite sure I get the full intent of your requirements but what do you think of this behavior?
trait TFactory{
def build():T
val description:String
}
trait T extends TFactory
//can't declare A without build and not make it abstract
class A(paramA: Int, paramB: Int, paramC: Int) extends T {
def build = new A(paramA, paramB, paramC)
val description = f"$paramA $paramB $paramC"
}
val a1 = new A(1, 4, 5)
val a2 = a1.build()
//We can give ourselves as a factory to something that expects TFactory
val factory:TFactory = a1
val a_new = factory.build()
//More likely we can just give our build method
def func(f: ()=>T) = {
val new_t = f()
new_t
}
val a_newer = func(a1.build)
println(a1 +": " + a1.description)
println(a2 +": " + a2.description)
println(a_new +": " + a_new.description)
println(a_newer +": " + a_newer.description)
Output:
Main$$anon$1$A#69267649: 1 4 5
Main$$anon$1$A#69b1fbf4: 1 4 5
Main$$anon$1$A#24148662: 1 4 5
Main$$anon$1$A#3f829e6f: 1 4 5
Add a representation type parameter:
trait Factory[Prod] {
def build(): Prod
}
trait Prod[Repr] {
def factory: Factory[Repr]
}
Or, if you want to "enforce" that the type remains the same (I wouldn't do that unless you gain something from it):
trait Prod[Repr <: Prod[Repr]] {
def factory: Factory[Repr]
}
Then:
case class AConfig(a: Int, b: Int)
case class A(config: AConfig) extends Prod[A] {
def factory = AFactory(config)
}
case class AFactory(config: AConfig) extends Factory[A] {
def build() = A(config)
}
val f0 = AFactory(AConfig(1, 2))
val p0 = f0.build()
val f1 = p0.factory
val p1 = f1.build()
assert(p0 == p1)
Recently I've (finally) started using Scala's Numeric trait, which does wonders. For example:
def square[A](x: A)(implicit num: Numeric[A]): A = num.times(x, x)
Now I can square any number be it Double, Integer, BigDecimal, or what not. Yet what if I want to do some more advanced math? For example, my logistic function for Double numbers looks like this:
def logisticFunction(x: Double): Double = 1.0 / (1.0 + math.exp(-x))
I could do the adding and dividing easily (I'd just have to use trait Fractional instead of Numeric), but what about the exponent? I sure don't want to write my own exp function (or any arbitrary function which takes Double arguments).
So, my question is this: how do I convert my A to Double, do my maths on that, and then convert back to A. Is it even possible?
EDIT:
That's how the signature of my function should look like:
def logisticFunction[A](x: A)(implicit num: Fractional[A]): A =
/* Magic happens here */
I've figured out the part about converting to double, which is as easy as num.toDouble(x). However the problem of converting back to A remains.
I still doubt this approach is really useful. But with your description, you will want something like this:
type FromDouble[A] = Double => A
type ToDouble [A] = A => Double
def logisticFunction[A: FromDouble: ToDouble](x: A): A = 1.0 / (1.0 + math.exp(-x))
logisticFunction(0.5)
implicit def bigDecimalToDouble(b: BigDecimal) = b.toDouble
logisticFunction(BigDecimal(0.5))
Or with dedicated type class:
object FromDouble {
implicit object _Double extends FromDouble[Double] {
def apply(d: Double) = d
}
implicit object _BigDecimal extends FromDouble[BigDecimal] {
def apply(d: Double) = BigDecimal(d)
}
}
trait FromDouble[A] extends (Double => A)
object ToDouble {
implicit object _Double extends ToDouble[Double] {
def apply(d: Double) = d
}
implicit object _BigDecimal extends ToDouble[BigDecimal] {
def apply(b: BigDecimal) = b.toDouble
}
}
trait ToDouble[A] extends (A => Double)
def logisticFunction[A: FromDouble: ToDouble](x: A): A = 1.0 / (1.0 + math.exp(-x))
logisticFunction(0.5)
logisticFunction(BigDecimal(0.5))
You will need a type class that provides trigonometric functions such as exp. Scala's standard library does not go beyond Fractional. You could try to use Spire.
Example:
$ sbt core/console
import spire.math._
import spire.algebra._
import spire.implicits._
def logisticFunction[A](x: A)(implicit m: Field[A], t: Trig[A]): A =
m.one / (m.one + exp(-x))
logisticFunction(0.5)
logisticFunction(BigDecimal(0.5))
I'm having difficulty transitioning from the world of C++/Templates to scala. I'm used to being able to use any operation on a template parameter T that I want, as long as anything I use to instantiate T with supports those operations (compile-time Duck typing, basically). I cannot find the corresponding idiom in Scala that will allow me to define an abstract class with a single type parameter, and which expects a certain interface for type T.
What I have almost works, but I cannot figure out how to tell the abstract class (Texture[T <: Summable[T]]) that T supports conversion/construction from an Int. How can I add the implicit conversion to the trait Summable so that Texture knows T supports the conversion?
trait Summable[T] {
def += (v : T) : Unit
def -= (v : T) : Unit
}
object Int4 { implicit def int2Int4(i : Int) = new Int4(i, i, i, i) }
class Int4 (var x : Int, var y : Int, var z : Int, var w : Int) extends Summable[Int4] {
def this (v : Int) = this(v, v, v, v)
def += (v : Int4) : Unit = { x += v.x; y += v.y; z += v.z; w += v.w }
def -= (v : Int4) : Unit = { x -= v.x; y -= v.y; z -= v.z; w -= v.w }
}
abstract class Texture[Texel <: Summable[Texel]] {
var counter : Texel
def accumulate(v : Texel) : Unit = { counter += v }
def decrement() : Unit = { counter -= 1 } //< COMPILE ERROR HERE, fails to find implicit
}
class Int4Target extends Texture[Int4] {
var counter : Int4 = new Int4(0, 1, 2, 3)
}
You can define an implicit constructor parameter like this
abstract class Texture[Texel <: Summable[Texel]](implicit int2Texel: Int => Texel) {
//...
This essentially tells the compiler that in order to construct an instance of Texture, there must be an implicit conversion function available from Int to Texel. Assuming you have such a function defined somewhere in scope (which you do), you should no longer get a compile error.
Edit2: Ok I originally misread your code, you actually only need one implicit parameter from Int => Texel. Your code compiles for me with the above modification.
Edit: You'll actually need 2 conversion functions, one from Texel => Int and another from Int => Texel in order to properly reassign the var
A fundamental difference between C++ templates and anything in Scala is that C++ templates are compiled for each use -- that is, if you use a template with int and with double, then two different classes are compiled, and they are only compiled when some code actually makes use of it.
Scala, on the other hand, has separate compilation. Not as good as Java's, given JVM limitations, but still following the basic principle. So, if something has a type parameter, it's still compiled at declaration, and only one such class ever exists. That compiled code has to support all possible parameters than it can be called with, which makes for rather different restrictions than templates.
On the matter of traits and implicit conversions, traits do not support parameters, and implicit conversions (view bounds) are parameters. Instead, use a class.
It is not possible in scala to require an implicit conversion to exist for a type
parameter of a trait. There is a good reason for this. Suppose we defined a
trait like:
trait ATrait[T <% Int] {
def method(v: T) { println(v: Int) }
}
And then made instances of it in two places:
package place1 {
implicit def strToInt(s: String) = 5
val inst = new ATrait[String]
}
package place2 {
implicit def strToInt(s: String) = 6
val inst = new ATrait[String]
}
And then used these instances like:
val a = if (someTest) place1 else place2
a.method("Hello")
Should this print 5 or 6? That is, which implicit conversion should it use?
Implicits have to be found at compile time, but you don't know which implicit
conversion was present for the creation of the object.
In other words, implicits are provided by the scope in which they are used, not
by the objects they are used on; the latter would be impossible.
So, about your problem. Instead of using an implicit, you could use an ordinary
member:
trait Summable[T] {
def -= (v: T): Unit
def -= (v: Int) { this -= (encode(v)) }
def encode(i: Int): T
}
class Int4 (var x: Int, var y: Int, var z: Int, var w: Int) extends Summable[Int4] {
def -= (v : Int4) : Unit = { x -= v.x; y -= v.y; z -= v.z; w -= v.w }
def encode(i: Int) = Int4.int2Int4(i)
}
Now the decrement method compiles correctly.
Another way of saying this is, don't think of implicits as properties belonging
to a type (ie, "can be implicitly converted from an Int" isn't a property of
Int4). They are values, which can be identified using types.
Hope this helps.
Suppose that I want to write a case class Stepper as follows:
case class Stepper(step: Int) {def apply(x: Int) = x + step}
It comes with a nice toStringimplementation:
scala> Stepper(42).toString
res0: String = Stepper(42)
but it's not really a function:
scala> Some(2) map Stepper(2)
<console>:10: error: type mismatch;
found : Stepper
required: Int => ?
Some(2) map Stepper(2)
A workaround is to implement the Function trait...
case class Stepper(step: Int) extends (Int => Int) {def apply(x: Int) = x + step}
But then, I can't have for free a nice toString implementation anymore:
scala> Stepper(42).toString
res2: java.lang.String = <function1>
Then, the question is: can I have the best of these two worlds? Is there a solution where I have the nice toString implementation for free AND an implementation of trait Function. In other words, is there a way to apply the linearization in such a way that case class syntaxic sugar is applied at last?
The question is not really to do with linearisation. In case-classes toString is a method automatically generated by the compiler if and only if Any.toString is not overridden in the end-type.
However, the answer is partly to do with linearisation - we need to override Function1.toString with the method that would have been generated by compiler if not for the version introduced by Function1 :
trait ProperName extends Product {
override lazy val toString = scala.runtime.ScalaRunTime._toString(this)
}
// now just mix in ProperName and... magic!
case class Stepper(step: Int) extends (Int => Int) with ProperName {
def apply(x:Int) = x+step
}
Then
println(Some(2) map Stepper(2))
println(Stepper(2))
Will produce
Some(4)
Stepper(2)
Update
Here is a version of ProperName trait that doesn't rely on the undocumented API method:
trait ProperName extends Product {
override lazy val toString = {
val caseFields = {
val arity = productArity
def fields(from: Int): List[Any] =
if (from == arity) List()
else productElement(from) :: fields(from + 1)
fields(0)
}
caseFields.mkString(productPrefix + "(", ",", ")")
}
}
Alternative toString implementation is derived from the source code for the original _toString method scala.runtime.ScalaRunTime._toString.
Please note that this alternative implementation is still based on the assumption that a case class always extends Product trait. Although the latter holds true as of Scala 2.9.0 and is a fact that is known to and relied upon by some members of Scala community it's not formally documented as part of Scala Language Spec.
EDIT: What about overriding toString?
case class Stepper(step: Int) extends (Int => Int) {
def apply(x: Int) = x + step
override def toString = "Stepper(" + step + ")"
}
You can use an implicit conversion to have Stepper treated like a function only when necessary:
case class Stepper(step: Int) { def apply(x: Int) = x + step }
implicit def s2f(s: Stepper) = new Function[Int, Int] {
def apply(x: Int) = s.apply(x)
}
Now you get the case class's toString when you call Stepper(42).toString, but Some(2) map Stepper(2) also works as desired.
(Note that I've been more verbose than necessary above to keep the mechanics clear. You can also write implicit def s2f(s: Stepper) = s.apply _ or any number of other more concise formulations).