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
Related
Scala allows us to define implicit parameters. Based on the exact type the correct definition is chosen. In example below, 2 monoid instances are defined for the same Money type, MoneyAdditionMonoid for accumulation and MoneyCompareMonoid for comparison.
What is not clear, how Scala compiler undestands which monoid is used in the maxDebitOnDay and sumBalances functions? Can you please highlight this to me, I cannot understand it.
trait Monoid[T] {
def zero: T
def op(t1: T, t2: T): T
}
object Monoid {
def apply[T](implicit monoid: Monoid[T]) = monoid
implicit val IntAdditionMonoid = new Monoid[Int] {
val zero = 0
def op(i: Int, j: Int) = i + j
}
implicit val BigDecimalAdditionMonoid = new Monoid[BigDecimal] {
val zero = BigDecimal(0)
def op(i: BigDecimal, j: BigDecimal) = i + j
}
implicit def MapMonoid[K, V: Monoid] = new Monoid[Map[K, V]] {
def zero = Map.empty[K, V]
def op(m1: Map[K, V], m2: Map[K, V]) = m2.foldLeft(m1) { (a, e) =>
val (key, value) = e
a.get(key).map(v => a + ((key, implicitly[Monoid[V]].op(v, value)))).getOrElse(a + ((key, value)))
}
}
final val zeroMoney: Money = Money(Monoid[Map[Currency, BigDecimal]].zero)
implicit def MoneyAdditionMonoid = new Monoid[Money] {
val m = implicitly[Monoid[Map[Currency, BigDecimal]]]
def zero = zeroMoney
def op(m1: Money, m2: Money) = Money(m.op(m1.m, m2.m))
}
object MoneyOrdering extends Ordering[Money] {
def compare(a:Money, b:Money) = a.toBaseCurrency compare b.toBaseCurrency
}
import MoneyOrdering._
import scala.math.Ordering
implicit val MoneyCompareMonoid = new Monoid[Money] {
def zero = zeroMoney
def op(m1: Money, m2: Money) = if (gt(m1, m2)) m1 else m2
}
}
package monoids.monoid
import java.util.Date
sealed trait TransactionType
case object DR extends TransactionType
case object CR extends TransactionType
sealed trait Currency
case object USD extends Currency
case object JPY extends Currency
case object AUD extends Currency
case object INR extends Currency
object common {
type Amount = BigDecimal
}
import common._
case class Money(m: Map[Currency, Amount]) {
def toBaseCurrency: Amount = ???
}
trait Analytics[Transaction, Balance, Money] {
def maxDebitOnDay(txns: List[Transaction])(implicit m: Monoid[Money]): Money
def sumBalances(bs: List[Balance])(implicit m: Monoid[Money]): Money
}
case class Transaction(txid: String, accountNo: String, date: Date, amount: Money, txnType: TransactionType, status: Boolean)
case class Balance(b: Money)
object Analytics extends Analytics[Transaction, Balance, Money] {
import Monoid._
final val baseCurrency = USD
private def valueOf(txn: Transaction): Money = {
if (txn.status) txn.amount
else MoneyAdditionMonoid.op(txn.amount, Money(Map(baseCurrency -> BigDecimal(100))))
}
private def creditBalance(bal: Balance): Money = {
if (bal.b.toBaseCurrency > 0) bal.b else zeroMoney
}
def maxDebitOnDay(txns: List[Transaction])(implicit m: Monoid[Money]): Money = {
txns.filter(_.txnType == DR).foldLeft(m.zero) { (a, txn) => m.op(a, valueOf(txn)) }
}
def sumBalances(bs: List[Balance])(implicit m: Monoid[Money]): Money =
bs.foldLeft(m.zero) { (a, bal) => m.op(a, creditBalance(bal)) }
}
The example is from
Functional Reactive-Domain-Modeling
book.
The answer is found in the forum of the book: Explicit dictionary passing technique in listing 4.3
We must pass explicitly the implicit argument so:
ltx being a list of Transactions
maxDebitOnday(ltx)(Monoid.MoneyCompareMonoid)
lbs being a list of Balances
sumBalances(lbs)(Monoid.MoneyAdditionMonoid)
I am quite new to Scala and got a few unresolved problems with the following code:
object exprs{
println("Welcome to the Scala worksheet")
def show(e: Expr): String = e match {
case Number(x) => x.toString
case Sum(l, r) => show(l) + " + " + show(r)
}
show(Sum(Number(1), Number(44)))
}
trait Expr {
def isNumber: Boolean
def isSum: Boolean
def numValue: Int
def leftOp: Expr
def rightOp: Expr
def eval: Int = this match {
case Number(n) => n
case Sum(e1, e2) => e1.eval + e2.eval
}
}
class Number(n: Int) extends Expr {
override def isNumber: Boolean = true
override def isSum: Boolean = false
override def numValue: Int = n
override def leftOp: Expr = throw new Error("Number.leftOp")
override def rightOp: Expr = throw new Error("Number.rightOp")
}
class Sum(e1: Expr, e2: Expr) extends Expr {
override def isNumber: Boolean = false
override def isSum: Boolean = true
override def numValue: Int = e1.eval + e2.eval
override def leftOp: Expr = e1
override def rightOp: Expr = e2
}
I get the following errors:
Error: object Number is not a case class, nor does it have an unapply/unapplySeq member
Error: not found: value Sum
How to resolve them? Thanks in advance
In Scala case class are like class with extra goodies + some other properties.
For a normal class,
class A(i: Int, s: String)
You can not create its instance like this,
val a = A(5, "five") // this will not work
You will have to use new to create new instance.
val a = new A(5, "five")
Now lets say we have case class,
case class B(i: Int, s: String)
We can create a new instance of B like this,
val b = B(5, "five")
The reason this works with case class is because case class have an auto-created companion objects with them, which provides several utilities including an apply and unapply method.
So, this usage val b = B(5, "five") is actually val b = B.apply(5, "five"). And here B is not the class B but the companion object B which is actually provieds apply method.
Similarly Scala pattern matching uses the unapply (unapplySeq for SeqLike patterns) methods provided by companion object. And hence normal class instances do not work with pattern matching.
Lets say you wanted to defined a class and not a case class for some specific reason but still want to use them with pattern-matching etc, you can provide its companion object with the required methods by yourselves.
class C(val i: Int, val s: String) {
}
object C {
def apply(i: Int, s: String) = new C(i, s)
def unapply(c: C) = Some((c.i, c.s))
}
// now you can use any of the following to create instances,
val c1 = new C(5, "five")
val c2 = C.apply(5, "five")
val c3 = C(5, "five")
// you can also use pattern matching,
c1 match {
case C(i, s) => println(s"C with i = $i and s = $s")
}
c2 match {
case C(i, s) => println(s"C with i = $i and s = $s")
}
Also, as you are new to learning Scala you should read http://danielwestheide.com/scala/neophytes.html which is probably the best resource for any Scala beginner.
tl;dr: Is there a way to automatically apply a type class recursively until no changes are performed anymore?
I have defined case classes that represent symbolic computations like this
trait SymbolicComputation
case class ConstZero() extends SymbolicComputation
case class Const[T](t: T) extends SymbolicComputation
case class Sum[S1, S2](s1: S1, s2: S2) extends SymbolicComputation
case class Product[F1, F2](f1: F1, f2: F2) extends SymbolicComputation
// ...
along with a type class to simplify trees of such computations
trait CanSimplify[-F] {
type R
def simplify(f: F): R
}
trait LowestPriorityCanSimplify {
// Cannot simplify any further
implicit def canSimplifyIdentity[F] = new CanSimplify[F] {
type R = F
def simplify(f: F) = f
}
}
trait LowPriorityCanSimplify extends LowestPriorityCanSimplify {
// Simplify summands
implicit def canSimplifySummands[F1, F2](
implicit canSimplifyFirst: CanSimplify[F1],
canSimplifySecond: CanSimplify[F2]
) = new CanSimplify[Sum[F1, F2]] {
type R = Sum[canSimplifyFirst.R, canSimplifySecond.R]
def simplify(f: Sum[F1, F2]) = {
Sum(
canSimplifyFirst.simplify(f.s1),
canSimplifySecond.simplify(f.s2)
)
}
}
}
trait HighPriorityCanSimplify extends LowPriorityCanSimplify {
// 0 + x = x
implicit def canSimplifyZeroPlusF[F](
implicit canSimplify: CanSimplify[F]
) =
new CanSimplify[Sum[ConstZero, F]] {
type R = canSimplify.R
def simplify(f: Sum[ConstZero, F]) = {
canSimplify.simplify(f.s2)
}
}
// 0 * x = 0
implicit def canSimplifyZeroTimesF[F] =
new CanSimplify[Product[ConstZero, F]] {
type R = ConstZero
def simplify(f: Product[ConstZero, F]) = {
ConstZero()
}
}
}
object CanSimplify extends HighPriorityCanSimplify {
implicit class RichSimplifiable[F](f: F) {
def simplify(implicit canSimplify: CanSimplify[F]) =
canSimplify.simplify(f)
}
}
Now when applying once, one iteration of simplification is performed correctly
import CanSimplify._
val s = Sum(ConstZero(), Sum(Product(ConstZero(), Const(2.0)), Const(1.0)))
// => s: Sum[ConstZero,Sum[Product[ConstZero,Const[Double]],Const[Double]]] = Sum(ConstZero(),Sum(Product(ConstZero(),Const(2.0)),Const(1.0)))
s.simplify
// => res0: Sum[ConstZero,Const[Double]] = Sum(ConstZero(),Const(1.0))
But actually, we need multiple (in this case 2) iterations to get to the simplest form
s.simplify.simplify
// => res1: Const[Double] = Const(1.0)
One idea that is not elegant but could work is to add a type-level integer (Nat) type parameter to CanSimplify and reduce that type parameter in every implicit application. Then one could start with a high number (the maximum number of simplifications that should be made) and stop only when the second parameter reaches _0.
Is there a nicer solution to this problem?
I would ensure that a method should only accept instances of A or B or C. And I don't want to modify the code of A, B and C.
case class A
case class B
case class C
def method(aOrbOrc: Any) = ???
// method("toto") should not compile
You can use Type Class.
case class A(s: String)
case class B(i: Int)
case class C(i1: Int, i2: Int)
// Type Class
trait ABC[T] {
def bar(t: T): String
}
// Instances
implicit object ABC_A extends ABC[A] {
override def bar(t: A): String = "A : s = " + t.s
}
implicit object ABC_B extends ABC[B] {
override def bar(t: B): String = "B : i = " + t.i
}
implicit object ABC_C extends ABC[C] {
override def bar(t: C): String = "C : i1 = " + t.i1 + ", i2 = " + t.i2
}
def method[T](abc: T)(implicit instance: ABC[T]) = println(instance.bar(abc))
method(A("AAAAA")) // => A : s = AAAAA
method(B(123)) // => B : i = 123
method(C(9, 5)) // => C : i1 = 9, i2 = 5
method(1) // compilation error
You could use Miles Sabin's idea for implementing union types (code below is taken from Rex Kerr's variant):
trait Contra[-A] {}
type Union[A,B,C] = {
type Check[Z] = Contra[Contra[Z]] <:< Contra[Contra[A] with Contra[B] with Contra[C]]
}
then do:
def method[T: Union[A,B,C]#Check](t: T) = ???
for example:
def method[T: Union[Int,String,Boolean]#Check](t:T) = ???
method(1) // OK
method("foo") // OK
method(true) // OK
method(1.5) // does not compile
Read more about it here. And here is a link to Miles' post.
def createFloatBuffer(data: Option[Quaternion]*): Option[FloatBuffer] = data match {
...
}
def createFloatBuffer(data: Option[Vector3f]*): Option[FloatBuffer] = data match {
...
}
This code will not compile due to the two methods having the same method signature. None type would not know which method to call.
I could just rename the methods, however I would like to this overloading style in my code.
After type erasure this two methods become createFloatBuffer(data: Option), and all types information is lost and not available at run time.
As a workaround I can suggest you to use TypeClass pattern.
case class Quaternion(v: Int)
case class Vector3f(v: Int)
case class FloatBuffer(v: Int)
sealed trait FloatBufferBuilder[T] {
def createFloatBuffer(data: Option[T]): Option[FloatBuffer]
}
implicit object QuaternionFloatBufferBuilder extends FloatBufferBuilder[Quaternion] {
def createFloatBuffer(data: Option[Quaternion]) = data.map(d => FloatBuffer(d.v))
}
implicit object Vector3fFloatBufferBuilder extends FloatBufferBuilder[Vector3f] {
def createFloatBuffer(data: Option[Vector3f]) = data.map(d => FloatBuffer(d.v))
}
def createFloatBuffer[T : FloatBufferBuilder](data: Option[T]): Option[FloatBuffer] =
implicitly[FloatBufferBuilder[T]].createFloatBuffer(data)
println(createFloatBuffer(Some(Quaternion(1))))
println(createFloatBuffer(Some(Vector3f(1))))
Magnet Pattern could also interesting for you: http://spray.io/blog/2012-12-13-the-magnet-pattern/
This is the use case for:
scala> object X { def f(is: Int*) = 42 ; def f(ds: Double*) = 43 }
<console>:10: error: double definition:
def f(is: Int*): Int at line 10 and
def f(ds: Double*): Int at line 10
have same type after erasure: (is: Seq)Int
object X { def f(is: Int*) = 42 ; def f(ds: Double*) = 43 }
^
scala> object X { def f(is: Int*) = 42 ; def f(ds: Double*)(implicit dummy: DummyImplicit) = 43 }
defined object X
scala> X f 1
res2: Int = 42
scala> X f 1.0
res3: Int = 43