Scala: Function argument Int or Double, how to make it generic? - scala

I'm almost sure there is already an answer, but being a beginner in Scala I cannot find it.
So, I've made a power function of two arguments:
def power(x: Double, n: Int): Double = {
#scala.annotation.tailrec
def go(acc: Double, i: Int): Double = {
if (i == 0) acc
else go(acc * x, i - 1)
}
go(1, n)
}
If I then calculate power(2, 3)
println(
power(2, 3)
)
I get 8.0, which is OK, but it would be better to have just 8 if the first argument is Int. How can I achieve that?

You can use Numeric
def power[T](x: T, n: Int)(implicit num: Numeric[T]): T = {
import num._
#scala.annotation.tailrec
def go(acc: T, i: Int): T = {
if (i == 0) acc
else go(acc * x, i - 1)
}
go(fromInt(1), n)
}
power(2, 3) // 8: Int
The magic of type class

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.

Why there can be only one implementation of a typeclass for any given type parameter?

I'm reading the FP for Mortals book which has following line:
There can only be one implementation of a typeclass for any given type parameter, a property known as typeclass coherence. Typeclasses look superficially similar to algebraic interfaces from the previous chapter, but algebras do not have to be coherent.
I do not understand this paragraph fully. Suppose we have following typeclass:
trait Ordering[T] {
def compare(x: T, y: T): Int
}
I can create two implementations for the Int type like this:
val ord1: Ordering[Int] = new Ordering[Int] {
def compare(x: Int, y: Int): Int =
if (x > y) 1 else if (x == y) 0 else -1
}
val ord2: Ordering[Int] = new Ordering[Int] {
def compare(x: Int, y: Int): Int =
if (x > y) -1 else if (x == y) 0 else 1
}
What do authors mean when they say that typeclass can have only one implementation? It doesn't apply for instances of the typeclass as we can have multiple ones for the same type. To what it is applied? Also why ADTs are not coherent in that sense?
Instances of a type class are defined as implicits.
implicit val ord1: Ordering[Int] = new Ordering[Int] {
def compare(x: Int, y: Int): Int =
if (x > y) 1 else if (x == y) 0 else -1
}
implicit val ord2: Ordering[Int] = new Ordering[Int] {
def compare(x: Int, y: Int): Int =
if (x > y) -1 else if (x == y) 0 else 1
}
If you ask implicitly[Ordering[Int]] you'll have
Error: ambiguous implicit values:
both value ord1 in object App of type => App.Ordering[Int]
and value ord2 in object App of type => App.Ordering[Int]
match expected type App.Ordering[Int]

Scala tail recursion

I have a function in scala that I wonder if it's possible to make into a tail recursive function.
def get_f(f: Int => Int, x: Int, y: Int): Int = x match {
case 0 => y
case _ => f(get_f(f, x - 1, y))
}
I see that this function applies f function to result recursivly, x times. It's the same as applying it to y, x times. Also I suggest you to use if else instead of pattern matching.
#tailrec
def get_f(f: Int => Int, x: Int, y: Int): Int =
if(x == 0) y
else get_f(f, x - 1, f(y))
Add #tailrec annotation to ensure that it is tail recursive
It is possible but the way you've constructed it means you're going to have to use a Trampolined style to make it work:
import scala.util.control.TailCalls._
def get_f(f: Int => Int, x: Int, y: Int): TailRec[Int] = x match {
case 0 => done(y)
case _ => tailcall(get_f(f, x - 1, y)).map(f)
}
val answer = get_f(_+1, 0, 24).result
You can read about TailRec here or for more advanced study, this paper.
Let's start with reducing number of parameters from your non-tailrec version to make it clear what it actually does:
def get_f(f: Int => Int, x: Int, y: Int) = {
def get_f_impl(x: Int): Int = x match {
case 0 => y
case _ => f(get_f_impl(x - 1))
}
get_f_impl(x)
}
The idea is that actually you apply f-function x-times to initial value y. So, it becomes clear that you can do something like this in order to make it tail-recursive:
def get_f(f: Int => Int, x: Int, y: Int) = {
#tailrec def get_f_impl(acc: Int, x: Int): Int =
if (x == 0) acc else get_f_impl(f(acc), x - 1)
get_f_impl(y, x)
}
REPL investigation:
Your original implementation:
scala> get_f(_ + 1, 4, 0)
res6: Int = 4
Your implementation (with params optimisation):
scala> get_f(_ + 1, 4, 0)
res0: Int = 4
Tailrec implementation:
scala> get_f(_ + 1, 4, 0)
res3: Int = 4
P.S. For more complex cases trampolines might fit: https://espinhogr.github.io/scala/2015/07/12/trampolines-in-scala.html
P.S.2 You can also try:
Scala - compose function n times
#adamw noticed that it will allocate n-sized list, so might not be very efficient
Endo.mulitply in scalaz (your f: Int => Int is actually an endomorphism): https://stackoverflow.com/a/7530783/1809978 - not sure about efficiency
I'll add that you can achieve the same result by using foldLeft on Range, like this:
def get_f(f: Int => Int, x: Int, y: Int) =
(0 until x).foldLeft(y)((acc, _) => f(acc))
In line with previous responses
def get_f2( f: Int => Int, x: Int, y: Int) : Int = {
def tail(y: Int, x: Int)(f: Int => Int) : Int = {
x match {
case 0 => y
case _ => tail(f(y), x - 1)(f) : Int
}
}
tail(y, x)(f)
}

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

scala: operation overload and implicit conversion clarification

Here is a code sample. Not sure why I am getting error when using multiplication.
Should I add implicit conversion to Int ? Sure the answer is simple!!
Thanks
class Fraction(val x:Int, val y:Int)
{
def X = x
def Y = y
implicit def int2Fraction(n: Int) = Fraction(n, 1)
def *(that: Fraction) : Fraction = new Fraction(that.X * X, that.Y * Y)
}
object Fraction {
def apply(x: Int, y: Int) = new Fraction(x, y)
}
val x : Int = 3
val result = x * Fraction(4, 5)
println( result.X )
Your implicit conversion function is a member of the Fraction class - so it can't be called without an instance of Fraction. If you move it to the object, it would work as expected:
object Fraction {
def apply(x: Int, y: Int) = new Fraction(x, y)
implicit def int2Fraction(n: Int) = Fraction(n, 1)
}
For an implicit conversion to take place, it needs to be in scope. Try taking it outside the class like this:
implicit def int2Fraction(n: Int) = Fraction(n, 1)
class Fraction(val x:Int, val y:Int)
{
def X = x
def Y = y
def *(that: Fraction) : Fraction = new Fraction(that.X * X, that.Y * Y)
}
object Fraction {
def apply(x: Int, y: Int) = new Fraction(x, y)
}
You can also put it inside the companion object; the compiler searches there automatically.