how to aggregate case-class in scala gracefully? - scala

case class value(x1:Long, x2: Double, ..., xk: Long, ... ,xn:Int) {
def add(rValue: Value): Value = {
Value(
x1 = x1 + rValue.x1,
...
xk = xk + rValue.xk,
...
xn = xn + rvalu.xn
)
}
}
I want to aggregate case-class('value'), I think this manual implementation is not elegant when n is large (such as n = 500?)

Here is a solution works in Scala3 with build-in api only:
trait Add[N] { def add(x: N, y: N): N }
object Add:
import scala.deriving.Mirror.ProductOf
given Add[Int] = _ + _
given Add[Long] = _ + _
given Add[Float] = _ + _
given Add[Double] = _ + _
given Add[EmptyTuple] = (_, _) => EmptyTuple
given [H, T <: Tuple](using ha: Add[H], ta: Add[T]): Add[H *: T] =
case (hx*:tx, hy*:ty) => ha.add(hx, hy) *: ta.add(tx, ty)
given [P <: Product](using p: ProductOf[P], a: Add[p.MirroredElemTypes]): Add[P] =
(x, y) => p.fromProduct(a.add(Tuple.fromProductTyped(x), Tuple.fromProductTyped(y)))
Then we can define Value class as:
scala> case class Value(x1: Int, x2: Float, x3: Double):
| def add(that: Value): Value = summon[Add[Value]].add(this, that)
|
scala> Value(1, 2, 3).add(Value(3, 4, 5))
val res0: Value = Value(4,6.0,8.0)

Fields in case classes are immutable, return a new instance with all the updated fields.
case class Value(x: Int, y: Int) {
def + (other: Value): Value =
Value(x + other.x, y + other.y)
}
Value(10, 20) + Value(10, 20)
//res0: Value = Value(20,40)
Value(10, 20) + Value(20, 30) + Value(30, 50)
//res1: Value = Value(60,100)

Related

How to use given in Dotty?

I was looking at Dotty docs under Contextual Abstractions page and I saw the Given Instances.
Given instances (or, simply, "givens") define "canonical" values of
certain types that serve for synthesizing arguments to given clauses.
Example:
trait Ord[T] {
def compare(x: T, y: T): Int
def (x: T) < (y: T) = compare(x, y) < 0
def (x: T) > (y: T) = compare(x, y) > 0
}
given intOrd: Ord[Int] {
def compare(x: Int, y: Int) =
if (x < y) -1 else if (x > y) +1 else 0
}
given listOrd[T]: (ord: Ord[T]) => Ord[List[T]] {
def compare(xs: List[T], ys: List[T]): Int = (xs, ys) match {
case (Nil, Nil) => 0
case (Nil, _) => -1
case (_, Nil) => +1
case (x :: xs1, y :: ys1) =>
val fst = ord.compare(x, y)
if (fst != 0) fst else compare(xs1, ys1)
}
}
But this example from docs never explains how to use given. I pulled the test Dotty example project and try yo use it, but I don't quite understand it.
Is it a new keyword ? Do we import it ? Or am I missing something .
Here's an example of using the given instance. Let's say we want to compare two integers, and see which is bigger than the other. We can leverage the already defined intOrd above and write:
def whichIsBigger[T](x: T, y: T)(given ord: Ord[T]): String = {
ord.compare(x, y) match {
case -1 => s"$x is less than $y"
case 0 => s"$x and $y are equal"
case 1 => s"$x is greater than $y"
}
}
println(whichIsBigger(2, 1))
Which yields:
2 is greater than 1
We were able to do this because there was a named given instance in scope, otherwise, the compiler would have complained it doesn't have an Ord[Int].
Is it a new keyword ? Do we import it ? Or am I missing something.
It is a new keyword, one which replaces a specific part of implicit definition in Scala 2. If this was Scala 2, we would have written:
implicit val intOrd: Ord[Int] = new Ord[Int] {
def compare(x: Int, y: Int) =
if (x < y) -1 else if (x > y) 1 else 0
}
def whichIsBigger[T](x: T, y: T)(implicit ord: Ord[T]): String
Perhaps it would be instructive to compare how we might define a typeclass using implicit keyword in Scala 2 versus using given keyword in Scala 3:
Scala 2
trait Semigroup[A] {
def combine(x: A, y: A): A
}
object Semigroup {
def combine[A: Semigroup](x: A, y: A) = implicitly[Semigroup[A]].combine(x,y)
implicit val intSemigroup: Semigroup[Int] = new Semigroup[Int] {
def combine(x: Int, y: Int) = x + y
}
implicit val quxSemigroup: Semigroup[Qux] = new Semigroup[Qux] {
def combine(x: Qux, y: Qux) = Qux(x.a + y.a)
}
}
case class Qux(a: Int)
Semigroup.combine(41, 1)
Semigroup.combine(Qux(41), Qux(1))
Scala 3
trait Semigroup[A] {
def combine(x: A, y: A): A
}
object Semigroup {
def combine[A](x: A, y: A)(given Semigroup[A]) = summon.combine(x,y)
given intSemigroup: Semigroup[Int] {
def combine(x: Int, y: Int) = x + y
}
given quxSemigroup: Semigroup[Qux] {
def combine(x: Qux, y: Qux) = Qux(x.a + y.a)
}
}
case class Qux(a: Int)
Semigroup.combine(41, 1))
Semigroup.combine(Qux(41), Qux(1))
Yes, it's a new keyword, as you can tell from 'given' being used in the grammar at the end of the page (section "Syntax"). It is intended to replace implicit. If you are already familiar with implicits, I think Relationship with Scala 2 Implicits is good to start with.

How to reduce the unwanted type parameter in a generic method?

I want to implement some generic math functions with some flexible.
e.g. a function named meandot which declared as something like
object Calc {
def meandot[..](xs: Array[Left], ys: Array[Right])(implicit ..): Result
}
where meandot(xs, ys) = sum(x*y for x, y in zip(xs, ys)) / length
When I invoke the meandot without specialized type parameter, it should return a value with default type. e.g.
scala> Calc.meandot(Array(1, 2), Array(1, 1))
res0: Int = 1
If I invoke the meandot with specialized type parameter, it can return a proper value.
scala> Calc.meandot[Int, Int, Double](Array(1, 2), Array(1, 1))
res1: Double = 1.5
However, the first two type parameters in above are redundant. The only type I need to specialized is the return type. I want to invoke it simplified as
scala> Calc.meandot2(Array(1, 2), Array(1, 1))
res2: Int = 1
scala> Calc.meandot2[Double](Array(1, 2), Array(1, 1))
res3: Double = 1.5
And I found a way to implement it as following code, which using a proxy class MeanDotImp. But it seems not so elegant. So I wonder if there is any better solution to reduce the unwanted type parameter in a generic method?
trait Times[L, R, N] {
def times(x: L, y: R): N
}
trait Num[N] {
def zero: N = fromInt(0)
def one: N = fromInt(1)
def fromInt(i: Int): N
def plus(x: N, y: N): N
def div(x: N, y: N): N
}
abstract class LowTimesImplicits {
implicit val IID: Times[Int, Int, Double] = new Times[Int, Int, Double] {
def times(x: Int, y: Int): Double = x * y
}
}
object Times extends LowTimesImplicits {
implicit val III: Times[Int, Int, Int] = new Times[Int, Int, Int] {
def times(x: Int, y: Int): Int = x * y
}
}
object Num {
implicit val INT: Num[Int] = new Num[Int] {
def fromInt(i: Int): Int = i
def plus(x: Int, y: Int): Int = x + y
def div(x: Int, y: Int): Int = x / y
}
implicit val DOU: Num[Double] = new Num[Double] {
def fromInt(i: Int): Double = i
def plus(x: Double, y: Double): Double = x + y
def div(x: Double, y: Double): Double = x / y
}
}
object Calc {
def meandot[L, R, N](xs: Array[L], ys: Array[R])
(implicit t: Times[L, R, N], n: Num[N]): N = {
val total = (xs, ys).zipped.foldLeft(n.zero){
case(r, (x, y)) => n.plus(r, t.times(x, y))
}
n.div(total, n.fromInt(xs.length))
}
implicit class MeanDotImp[L, R](val marker: Calc.type) {
def meandot2[N](xs: Array[L], ys: Array[R])
(implicit t: Times[L, R, N], n: Num[N]): N = {
val total = (xs, ys).zipped.foldLeft(n.zero){
case(r, (x, y)) => n.plus(r, t.times(x, y))
}
n.div(total, n.fromInt(xs.length))
}
}
}
An alternative solution is similar to yours, but is a bit more straightforward: it first fixes the type parameter that you want to be able to set and then infers the other two. To achieve that we can declare a class with apply method:
class meandot[N] {
def apply[L, R](xs: Array[L], ys: Array[R])
(implicit t: Times[L, R, N], n: Num[N]): N = ??? // your implementation
}
Now, to avoid writing new meandot, we can define a method which just instantiates this class:
object Calc {
def meandot[N]: meandot[N] = new meandot[N]
}
Elegance of this approach is arguable, but it's quite simple and doesn't involve implicits. Here's a usage demo:
scala> Calc.meandot(Array(1,2,3), Array(4,5,6))
res0: Int = 10
scala> Calc.meandot[Double](Array(1,2,3), Array(4,5,6))
res1: Double = 10.666666666666666

How can I pass the parameter in the function num()?

object MatchTest4 extends App{
def matchTest(x: Any): Any = x match {
case 1 => def num(p: Int, q: Int): Unit = {
val sum = p + q
println(sum)
}
case 2 => def num(p: Int, q: Int): Unit = {
val sub = p - q
println(sub)
}
case 3 => def num(p: Int, q: Int): Unit = {
val mul = p * q
println(mul)
}
case 4 => def num(p: Int, q: Int): Unit = {
val div = p / q
println(div)
}
case _ => println("Invalid Choice")
}
println("Enter Your Choice")
val b= readInt()
println(matchTest(b))
}
Now I want to give parameter to the function num().Is it possible?
The below code should accomplish what you are trying to do. The changes I made were:
Removed the return type for the matchTest. Scala will automatically infer the return type as a function value.
Replaced the method definitions "num" by anonymous functions.
Modified the signature of your wildcard pattern match to also return a function consistent with other pattern matches. (This is a hack, I hope someone knows a better way)
You can run your returned anonymous functions like matchTest(4)(2,3) etc.
def matchTest(x: Any) = x match {
case 1 => (p: Int, q: Int) => {
val sum = p + q
println(sum)
}
case 2 => (p: Int, q: Int) => {
val sub = p - q
println(sub)
}
case 3 => (p: Int, q: Int) => {
val mul = p * q
println(mul)
}
case 4 => (p: Int, q: Int) => {
val div = p / q
println(div)
}
case _ => println("Invalid Choice"); (a: Int, b: Int) => println("Invalid Choice")
}

Generate prime factors of a number in Scala

How can I generate the factors of an integer in Scala? Here's my take 1:
def factorize(x: Int): List[Int] = {
def foo(x: Int, a: Int): List[Int] = {
if (a > Math.pow(x, 0.5))
return List(x)
x % a match {
case 0 => a :: foo(x / a, a)
case _ => foo(x, a + 1)
}
}
foo(x, 2)
}
factorize(360) // List(2, 2, 2, 3, 3, 5)
Take 2 based on comments from #SpiderPig and #seth-tisue
def factorize(x: Int): List[Int] = {
def foo(x: Int, a: Int): List[Int] = {
(a*a < x, x % a) match {
case (true, 0) => a :: foo(x/a, a)
case (true, _) => foo(x, a+1)
case (false, _) => List(x)
}
}
foo(x, 2)
}
A tail recursive solution:
def factorize(x: Int): List[Int] = {
#tailrec
def foo(x: Int, a: Int = 2, list: List[Int] = Nil): List[Int] = a*a > x match {
case false if x % a == 0 => foo(x / a, a , a :: list)
case false => foo(x , a + 1, list)
case true => x :: list
}
foo(x)
}
Just little improvement of "Take 2" from the question:
def factorize(x: Int): List[Int] = {
def foo(x: Int, a: Int): List[Int] = x % a match {
case _ if a * a > x => List(x)
case 0 => a :: foo(x / a, a)
case _ => foo(x, a + 1)
}
foo(x, 2)
}
Also, the following method may be a little faster (no x % a calculation in the last iteration):
def factorize(x: Int): List[Int] = {
def foo(x: Int, a: Int): List[Int] = if (a * a > x) List(x) else
x % a match {
case 0 => a :: foo(x / a, a)
case _ => foo(x, a + 1)
}
foo(x, 2)
}

How to declare implicit arguments in higher order functions?

I want IMPLICIT args in a higher order function, like:
func(arg1) { implicit (x, y) => x * y }
But the compiler says:
error: expected start of definition
val a = func("2", "4") { implicit (x, y) =>
^
java version "1.7.0_40"
Scala code runner version 2.10.2-RC2 -- Copyright 2002-2013, LAMP/EPFL
The runnable sample code:
object Test extends App {
new Test().run
}
class Test {
def run = {
val a = func("2", "4") { (x, y) => // It's OK
x * y
}
println("a: " + a)
val b = gunc("2", "4") { implicit x => { implicit y => // It's OK
x * y
}}
println("b: " + b)
}
def func(x: String, y: String)(f: (Int, Int) => Int) = f(x.toInt, y.toInt)
def gunc(x: String, y: String)(g: Int => Int => Int) = g(x.toInt)(y.toInt)
def hunc(x: String, y: String)(h: Tuple2[Int, Int] => Int) = h((x.toInt, y.toInt))
}
[ADD COMMENT]
I wonder...
We can declare as "implicit x => ..." with one arg.
It seems there is no way to declare two implicit args.
Try adding:
val c = hunc("2", "4") { implicit pair => pair._1 * pair._2 }
When you say implicit y => y * 2 you're not
declaring an implicit argument but mark the function as implicit,
so you make an analog to this:
implicit val f1 = (y: Int) => y * 2
def func1(x: String, y: String)(f: Int => Int) = f(1)
func1("", "")(f1)
When you want to mark a function with two
arguments as implicit you can do it this way:
implicit val f2 = (x: Int, y: Int) => y * 2
def func2(x: String, y: String)(f: (Int, Int) => Int) = f(1, 2)
func2("", "")(f2)
But you cannot do it so:
func2("", "")(implicit (x, y) => x), in this particular case I just don't see any meaning to use implicits.
Also you can see this question, maybe you'll find some useful information there