Modelling of C++ concepts with Scala traits - scala

There are some examples of using Scala traits like C++ concepts and Haskell type classes in paper «Type Classes as Objects and Implicits». I try to write something like InputIterator concept and find function in Scala:
concept InputIterator<typename Iter> {
typename value_type;
value_type operator*(Iter);
...
};
template<typename Iter, typename V>
requires InputIterator<Iter> && EqualityComparable<Iter::value_type, V>
Iter find(Iter first, Iter last, V v) {
while (first < last && *first != v)
++first;
return first;
}
I'm not sure I understand traits correctly. But still... There is InputIterator trait written in Scala (or more exactly — it's simplified analogue with methods used in find function):
trait InputIterator[Iter] {
type value_type
def <(a: Iter, b: Iter): Boolean
def ++(it: Iter): Unit
def *(it: Iter): value_type
}
EqualityComparable is clear:
trait EqualityComparable[S, T] {
def ==(s: S, t: T): Boolean
def !=(s: S, t: T): Boolean = !(s == t)
}
But what should we do with find? I would like to write something like this:
def find[Iter, V](first: Iter, last: Iter, x: V)(implicit iterator: InputIterator[Iter],
cmp: EqualityComparable[iterator.value_type, V]): Iter =
{
while (iterator.<(first, last) && cmp.!=(iterator.*(first), x))
iterator.++(first)
first
}
But it causes an error «illegal dependent method type». And I don't know how to «extract» abstract type value_type other way. So as a result I have got this code:
trait EqualityComparable[S, T] {
def ==(s: S, t: T): Boolean
def !=(s: S, t: T): Boolean = !(s == t)
}
trait InputIterator[Iter] {
type value_type
def <(a: Iter, b: Iter): Boolean
def ++(it: Iter): Unit
def *(it: Iter): value_type
}
trait VTInputIterator[Iter, VT] extends InputIterator[Iter] {
type value_type = VT
}
class ArrayListIterator[T](a: ArrayList[T], i: Int) {
val arr: ArrayList[T] = a
var ind: Int = i
def curr(): T = arr.get(ind)
def ++(): Unit = { ind += 1 }
override def toString() = "[" + ind.toString() + "]"
}
class InputIterArrList[T] extends VTInputIterator[ArrayListIterator[T], T]{
def <(a: ArrayListIterator[T], b: ArrayListIterator[T]) = {
if (a.arr == b.arr) a.ind < b.ind
else throw new IllegalArgumentException()
}
def ++(it: ArrayListIterator[T]): Unit = it.++()
def *(it: ArrayListIterator[T]) = it.curr()
}
object TestInputIterator extends Application{
def find[Iter, VT, V](first: Iter, last: Iter, x: V)(implicit iterator: VTInputIterator[Iter, VT],
cmp: EqualityComparable[VT, V]): Iter =
{
while (iterator.<(first, last) && cmp.!=(iterator.*(first), x))
iterator.++(first)
first
}
implicit object EqIntInt extends EqualityComparable[Int, Int] {
def ==(a: Int, b: Int): Boolean = { a == b }
}
implicit object inputIterArrListInt extends InputIterArrList[Int]{}
val len = 10;
var arr: ArrayList[Int] = new ArrayList(len);
for (i: Int <- 1 to len)
arr.add(i)
var arrFirst = new ArrayListIterator(arr, 0)
var arrLast = new ArrayListIterator(arr, len)
var r = find(arrFirst, arrLast, 7)
println(r)
}
Instead of abstract type we used type parameter VT in def find[Iter, VT, V].
So the question is: how it can be done better? And is it possible to use abstract type value_type without additional type parameter VT?

Change the signature of find to:
def find[Iter, V, II <: InputIterator[Iter]](first: Iter, last: Iter, x: V)(
implicit iterator: II, cmp: EqualityComparable[II#value_type, V]): Iter
That's probably what you want to express.
Note that your Scala code is really not the same as the C++ code. In C++ find uses Iter::value_type but in Scala you use InputIterator[Iter]#value_type.

Related

Scala Method on Generic Data Type

I am trying to create a generic class that only accepts java.math.BigDecimal or Long. Here is the code:
class myClass[T]()
{
def display( x : T) = {
println(x.doubleValue())
}
}
val input = new java.math.BigDecimal(100)
// val input = 100L
val x = new myClass[java.math.BigDecimal]()
x.display(input)
Clearly I will have this error: ScalaFiddle.scala:22: error: value doubleValue is not a member of type parameter T.
I tried playing with implicit conversion, view bound, and context bound for hours. No result so far. Is there any way I can force Scala to believe me that T has method .doubleValue()? (java.big.Decimal and Long both has .doubleValue() method, but they don't share same super-class)
Try structural type bound
class myClass[T <: {def doubleValue(): Double}]
or type class
trait HasDoubleValue[T] {
def doubleValue(t: T): Double
}
object HasDoubleValue {
implicit val long: HasDoubleValue[Long] = t => t.doubleValue
implicit val bigDecimal: HasDoubleValue[BigDecimal] = t => t.doubleValue
}
implicit class DoubleValueOps[T: HasDoubleValue](x: T) {
def doubleValue(): Double = implicitly[HasDoubleValue[T]].doubleValue(x)
}
class myClass[T: HasDoubleValue]
In Dotty (Scala 3) we might use union types, for example,
class myClass[T <: (Long | java.math.BigDecimal)]() {
def display(x: T) =
println(
x match {
case t: Long => t.doubleValue
case t: java.math.BigDecimal => t.doubleValue
}
)
}
new myClass().display(new java.math.BigDecimal(100)) // OK
new myClass().display(100L) // OK
new myClass().display("100") // Error
scala> class C private (n: Number) {
| def this(i: Long) = this(i: Number)
| def this(b: BigDecimal) = this(b: Number)
| def d = n.doubleValue
| }
defined class C
scala> new C(42L).d
res0: Double = 42.0
scala> new C(BigDecimal("123456789")).d
res1: Double = 1.23456789E8
or with a type parameter
scala> class C[A <: Number] private (n: A) { def d = n.doubleValue ; def a = n } ; object C {
| def apply(i: Long) = new C(i: Number) ; def apply(b: BigDecimal) = new C(b) }
defined class C
defined object C

why scala compiler says type arguments does not conform to bounds?

I created Combiner trait with subclasses Complex and IntCombiner and my objective is to make Matrix work with both Complex and Int. But some reason it dosen't compile saying that
[com.implicits.TestImplicits1.IntCombiner] do not conform to class Matrix's type parameter bounds [T <: com.implicits.TestImplicits1.Combiner[T]]
val m1 = new Matrix[IntCombiner](3, 3)((1 to 9).sliding(3).map {
But as my understanding goes as IntContainer is the subclass of Combiner it should work. Why such an error please explain ?
object TestImplicits1 {
trait Combiner[T] {
def +(b: T): T
def *(b: T): T
}
class Complex(r: Double, i: Double) extends Combiner[Complex] {
val real = r
val im = i
override def +(b: Complex): Complex = {
new Complex(real + b.real, im + b.im)
}
override def *(b: Complex): Complex = {
new Complex((real * b.real) - (im * b.im), real * b.im + b.real * im)
}
}
class IntCombiner(a: Int) extends Combiner[Int] {
val v = a
override def *(b: Int): Int = v * b
override def +(b: Int): Int = v + b
}
class Matrix[T <: Combiner[T]](x1: Int, y1: Int)(ma: Seq[Seq[T]]) {
self =>
val x: Int = x1
val y: Int = y1
def dot(v1: Seq[T], v2: Seq[T]): T = {
v1.zip(v2).map { t: (T, T) => {
t._1 * t._2
}
}.reduce(_ + _)
}
}
object MatrixInt extends App {
def apply[T <: Combiner[T]](x1: Int, y1: Int)(s: Seq[Seq[T]]) = {
new Matrix[T](x1, y1)(s)
}
val m1 = new Matrix[IntCombiner](3, 3)((1 to 9).sliding(3).map {
x => x map { y => new IntCombiner(y) }
}.toSeq)
}
}
F-bounded polymorphism cannot be added to an existing Int class, because Int is just what it is, it does not know anything about your Combiner traits, so it cannot extend Combiner[Int]. You could wrap every Int into something like an IntWrapper <: Combiner[IntWrapper], but this would waste quite a bit of memory, and library design around F-bounded polymorphism tends to be tricky.
Here is a proposal based on ad-hoc polymorphism and typeclasses instead:
object TestImplicits1 {
trait Combiner[T] {
def +(a: T, b: T): T
def *(a: T, b: T): T
}
object syntax {
object combiner {
implicit class CombinerOps[A](a: A) {
def +(b: A)(implicit comb: Combiner[A]) = comb.+(a, b)
def *(b: A)(implicit comb: Combiner[A]) = comb.*(a, b)
}
}
}
case class Complex(re: Double, im: Double)
implicit val complexCombiner: Combiner[Complex] = new Combiner[Complex] {
override def +(a: Complex, b: Complex): Complex = {
Complex(a.re + b.re, a.im + b.im)
}
override def *(a: Complex, b: Complex): Complex = {
Complex((a.re * b.re) - (a.im * b.im), a.re * b.im + b.re * a.im)
}
}
implicit val intCombiner: Combiner[Int] = new Combiner[Int] {
override def *(a: Int, b: Int): Int = a * b
override def +(a: Int, b: Int): Int = a + b
}
class Matrix[T: Combiner](entries: Vector[Vector[T]]) {
def frobeniusNormSq: T = {
import syntax.combiner._
entries.map(_.map(x => x * x).reduce(_ + _)).reduce(_ + _)
}
}
}
I don't know what you attempted with dot there, your x1, x2 and ma seemed to be completely unused, so I added a simple square-of-Frobenius-norm example instead, just to show how the typeclasses and the syntactic sugar for operators work together. Please don't expect anything remotely resembling "high performance" from it - JVM traditionally never cared about rectangular arrays and number crunching (at least not on a single compute node; Spark & Co is a different story). At least your code won't be automatically transpiled to optimized CUDA code, that's for sure.

How to create object/singleton of generic type in Scala?

In the code shown below, how can I convert EmptyTree to object (Singleton) ?
trait Tree[T] {
def contains(num: T): Boolean
def inc( num: T ): Tree[T]
}
class EmptyTree[T <% Ordered[T] ] extends Tree[T] {
def contains(num:T):Boolean = false
def inc(num:T):Tree[T] = {
new DataTree(num, new EmptyTree, new EmptyTree)
}
override def toString = "."
}
class DataTree[T <% Ordered[T] ](val x:T, val left:Tree[T], val right:Tree[T]) extends Tree[T] {
def contains(num:T):Boolean = {
if( num < x ) left.contains(x)
else if ( num > x ) right.contains(x)
else true
}
def inc(num:T):Tree[T] = {
if(num < x ) new DataTree(x, left.inc(num), right)
else if ( num > x ) new DataTree(x, left, right.inc(num))
else this
}
override def toString = "{" + left + x + right + "}"
}
val t = new DataTree(20, new EmptyTree[Int], new EmptyTree[Int])
//> t : greeting.Test.DataTree[Int] = {.20.}
val p = t.inc(10) //> p : greeting.Test.Tree[Int] = {{.10.}20.}
val a = p.inc(30) //> a : greeting.Test.Tree[Int] = {{.10.}20{.30.}}
val s = a.inc(5) //> s : greeting.Test.Tree[Int] = {{{.5.}10.}20{.30.}}
val m = s.inc(11) //> m : greeting.Test.Tree[Int] = {{{.5.}10{.11.}}20{.30.}}
Let me detalize Alexey's answer. Here is full implementation with some code style improvements:
First define your trait with aknowledgment of its covariance:
trait Tree[+T] {
def contains[U >: T : Ordering](num: U): Boolean
def inc[U >: T : Ordering](num: U): Tree[U]
}
Next define your subtype-of-all-trees object
case object EmptyTree extends Tree[Nothing] {
def contains[U >: Nothing : Ordering](num: U): Boolean = false
def inc[U >: Nothing : Ordering](num: U): Tree[U] =
DataTree(num, EmptyTree, EmptyTree)
override def toString = "."
}
Now change your general case implementation:
case class DataTree[T: Ordering](x: T, left: Tree[T], right: Tree[T]) extends Tree[T] {
import Ordering.Implicits._
def contains[U >: T : Ordering](num: U): Boolean =
if (num < x) left.contains(x)
else if (num > x) right.contains(x)
else true
def inc[U >: T : Ordering](num: U): Tree[U] =
if (num < x) DataTree(x, left.inc(num), right)
else if (num > x) DataTree(x, left, right.inc(num))
else this
override def toString = "{" + left + x + right + "}"
}
You could be a little bit frustrated since I replaced your Ordered with Ordering, but you should know that view bounds are deprecated
You have to fix the generic argument because that's the only time you can provide it:
scala> trait A[T]
defined trait A
scala> object B extends A[Int]
defined object B
Obviously you want to reuse EmptyTree for all types of T, so instead of defining A[SOMETYPE] for each type just use bottom type Nothing:
scala> object B extends A[Nothing]
defined object B
This object can be used with any tree.
That's exactly how Option[T] is implemented in Scala. Here is how None is defined:
case object None extends Option[Nothing]
If keeping generics, also there is an option to add empty factory - like it's done for Map and Vector. Off course, with such an implementation it will not be a unique instance object for every creation, but when using inc method, it will not produce new objects, it will just reference itself.
object DataTree {
def empty[T <% Ordered[T]] = new Tree[T] {
def contains(num: T):Boolean = false
def inc(num: T): Tree[T] = {
new DataTree(num, this, this)
}
override def toString = "."
}
}
So you can instantiate it as following:
val t = new DataTree(20, DataTree.empty[Int], DataTree.empty[Int])

scala's spire framework : I am unable to operate on a group

I try to use spire, a math framework, but I have an error message:
import spire.algebra._
import spire.implicits._
trait AbGroup[A] extends Group[A]
final class Rationnel_Quadratique(val n1: Int = 2)(val coef: (Int, Int)) {
override def toString = {
coef match {
case (c, i) =>
s"$c + $i√$n"
}
}
def a() = coef._1
def b() = coef._2
def n() = n1
}
object Rationnel_Quadratique {
def apply(coef: (Int, Int),n: Int = 2)= {
new Rationnel_Quadratique(n)(coef)
}
}
object AbGroup {
implicit object RQAbGroup extends AbGroup[Rationnel_Quadratique] {
def +(a: Rationnel_Quadratique, b: Rationnel_Quadratique): Rationnel_Quadratique = Rationnel_Quadratique(coef=(a.a() + b.a(), a.b() + b.b()))
def inverse(a: Rationnel_Quadratique): Rationnel_Quadratique = Rationnel_Quadratique((-a.a(), -a.b()))
def id: Rationnel_Quadratique = Rationnel_Quadratique((0, 0))
}
}
object euler66_2 extends App {
val c = Rationnel_Quadratique((1, 2))
val d = Rationnel_Quadratique((3, 4))
val e = c + d
println(e)
}
the program is expected to add 1+2√2 and 3+4√2, but instead I have this error:
could not find implicit value for evidence parameter of type spire.algebra.AdditiveSemigroup[Rationnel_Quadratique]
val e = c + d
^
I think there is something essential I have missed (usage of implicits?)
It looks like you are not using Spire correctly.
Spire already has an AbGroup type, so you should be using that instead of redefining your own. Here's an example using a simple type I created called X.
import spire.implicits._
import spire.algebra._
case class X(n: BigInt)
object X {
implicit object XAbGroup extends AbGroup[X] {
def id: X = X(BigInt(0))
def op(lhs: X, rhs: X): X = X(lhs.n + rhs.n)
def inverse(lhs: X): X = X(-lhs.n)
}
}
def test(a: X, b: X): X = a |+| b
Note that with groups (as well as semigroups and monoids) you'd use |+| rather than +. To get plus, you'll want to define something with an AdditiveSemigroup (e.g. Semiring, or Ring, or Field or something).
You'll also use .inverse and |-| instead of unary and binary - if that makes sense.
Looking at your code, I am also not sure your actual number type is right. What will happen if I want to add two numbers with different values for n?
Anyway, hope this clears things up for you a bit.
EDIT: Since it seems like you're also getting hung up on Scala syntax, let me try to sketch a few designs that might work. First, there's always a more general solution:
import spire.implicits._
import spire.algebra._
import spire.math._
case class RQ(m: Map[Natural, SafeLong]) {
override def toString: String = m.map {
case (k, v) => if (k == 1) s"$v" else s"$v√$k" }.mkString(" + ")
}
object RQ {
implicit def abgroup[R <: Radical](implicit r: R): AbGroup[RQ] =
new AbGroup[RQ] {
def id: RQ = RQ(Map.empty)
def op(lhs: RQ, rhs: RQ): RQ = RQ(lhs.m + rhs.m)
def inverse(lhs: RQ): RQ = RQ(-lhs.m)
}
}
object Test {
def main(args: Array[String]) {
implicit val radical = _2
val x = RQ(Map(Natural(1) -> 1, Natural(2) -> 2))
val y = RQ(Map(Natural(1) -> 3, Natural(2) -> 4))
println(x)
println(y)
println(x |+| y)
}
}
This allows you to add different roots together without problem, at the cost of some indirection. You could also stick more closely to your design with something like this:
import spire.implicits._
import spire.algebra._
abstract class Radical(val n: Int) { override def toString: String = n.toString }
case object _2 extends Radical(2)
case object _3 extends Radical(3)
case class RQ[R <: Radical](a: Int, b: Int)(implicit r: R) {
override def toString: String = s"$a + $b√$r"
}
object RQ {
implicit def abgroup[R <: Radical](implicit r: R): AbGroup[RQ[R]] =
new AbGroup[RQ[R]] {
def id: RQ[R] = RQ[R](0, 0)
def op(lhs: RQ[R], rhs: RQ[R]): RQ[R] = RQ[R](lhs.a + rhs.a, lhs.b + rhs.b)
def inverse(lhs: RQ[R]): RQ[R] = RQ[R](-lhs.a, -lhs.b)
}
}
object Test {
def main(args: Array[String]) {
implicit val radical = _2
val x = RQ[_2.type](1, 2)
val y = RQ[_2.type](3, 4)
println(x)
println(y)
println(x |+| y)
}
}
This approach creates a fake type to represent whatever radical you are using (e.g. √2) and parameterizes QR on that type. This way you can be sure that no one will try to do additions that are invalid.
Hopefully one of these approaches will work for you.

New Instances of Decorated Instances

I have a set of decorator-traits (for simplicity here only trait T) mixing in classes (here subclasses of A).
trait T { def i: Int }
abstract class A
type AT = A with T
class B extends A
// class C extends A
// class D extends A
// ...
Now I have an instance a of e.g. class B which I handle as an instance of type AT (together with other A-subclass-AT-instances in a Seq[AT]).
val a: AT = new B with T { val i = 8 }
How can I generically decorate like this:
def toAT(a: A, i: Int): AT = {
// how to ???
}
An obvious solution I thought about is:
trait T { def i: Int }
abstract class A {
def asAT(i: Int): AT
}
class B extends A {
def asAT(ii: Int): AT = new B with T { val i = ii }
}
type AT = A with T
def toAT(a: A, i: Int): AT = a.asAT(i)
But I don´t want to pollute my classes B, C, ..., Z with a new method and there are other decorations, so for every decoration-combo I need a new method for all subclasses!
Is there a more generic way?
EDIT:
An example why I need the toAT method, but still with the obvious solution approach from above in terms of a redecorated method:
trait T { def b: Boolean}
type AT = A with T
abstract class A(val i: Int) {
def changedBy(x: Int): A
def redecorated(oldAT: AT): AT
}
class B(x: Int) extends A(x) {
def changedBy(x: Int): A = new B(i * x)
def redecorated(oldAT: AT): AT = new B(i) with T { val b = oldAT.b }
}
class C(x: Int) extends A(x) {
def changedBy(x: Int): A = new C(i * x * x)
def redecorated(oldAT: AT): AT = new C(i) with T { val b = oldAT.b }
}
val b = new B(1) with T { val b = true }
val c = new C(1) with T { val b = false }
val x = 8
val res: Seq[AT] = Seq(b,c) map { at => at.changedBy(x).redecorated(at) }
Basically, you can't do it.
One alternative is to use the auto proxy plugin, by Kevin Wright. See also here and here for more information about it.