I want to generalise this function
def selfSufficiency(a: Seq[Double], b: Seq[Double]): Double =
a.sum/b.sum
I tried using the ideas provided here to implement a more general function that work with Doubles, Floats, Ints, etc.:
def selfSufficiency[A](a: Seq[A], b: Seq[A])
(implicit n: Numeric[A]):A = {
import n._
a.sum/b.sum
}
I however get a remark from eclipse saying that
value / is not a member of type parameter A.
1- How can I implement this in functional/generalisable way?
2- Does my implementation limits the user to have the same type "A" for both inputs? In other words, can I do this with my code?
selfSufficiency(Seq(1,2,3), Seq(2.0,1.3))
if I cannot, please explain how to implement this?
Please note that the code here provide a toy example. In my production function, I add, subtract, find the larger number, etc.
The problem is that Numeric doesn't encode the division function - you need a Fractional.
Thus your code becomes
def selfSufficiency[A](a: Seq[A], b: Seq[A])
(implicit n: Fractional[A]):A = {
import n._
a.sum/b.sum
}
And now it works.
Edit
I just read this part of your question.
Does my implementation limits the user to have the same type "A" for both inputs? In other words, can I do this with my code?
Because both Fractional and Numeric are parametrized in just one T, both arguments have to be from the same type - for example take a look to the div function.
However, since numeric values of less precision are subtypes of the ones with higher (fig 1). You can make it work by upcast, but you will need to help the compiler a little more.
selfSufficiency[Double](Seq(1,2,3), Seq(2.0,1.3)) // res1: Double = 1.8181818181818183
Note: Without specifying the type as Double, the compiler will yield the following error.
error: could not find implicit value for parameter n: Fractional[AnyVal]
fig 1
Reference: https://www.artima.com/pins1ed/scalas-hierarchy.html
What you are looking for is the Fractional trait which is a more narrow Numeric (subtype) that supports div.
Related
I recently discovered Scala, and I've written an RK4 solver that I'm trying to generalize as much as possible. After getting it working with arbitrarily large systems, I wanted to get it working with arbitrary numeric data types -but I've run into a wall. When I use a generic data type, no matter what restrictions I place on it, Scala automatically converts everything to strings to use '+'.
Most of what I've tried thus far has ultimately been writing the same thing in different ways. I could explicitly convert everything to the highest precision type I'll be using (BigDecimal) and call it a day, but that misses much of the point of generalizing the function.
This isn't my entire RK4 program, but it is the one piece of code I've been screwing with for the past couple hours:
def vecSum[T : Numeric]( u: Vector[T], v: Vector[T]): Vector[T] = (u, v).zipped.map(_ + _)
It's the vector sum (math vector, the data structure is just coincidental), which takes in two vectors and returns a single vector where each element is the sum of the two corresponding elements in the input vectors.
I'm trying to get it to return a vector of the same numeric type as the inputs, but it only wants to spit out a vector of strings.
Use
def vecSum[T](u: Vector[T], v: Vector[T])(implicit o: Numeric[T]): Vector[T] = (u, v).zipped.map((x, y) => o.plus(x, y))
If you specifically want to use + you can use
import Numeric.Implicits._
def vecSum2[T: Numeric](u: Vector[T], v: Vector[T]): Vector[T] = {
(u, v).zipped.map((x, y) => x + y)
}
I'm experimenting with a method in Scala which is attempting to round numbers depending on how big they are, e.g. if the value is below 1 then it makes sense to round it by at least one decimal point; rather than remaining an integer. Here's what I'm trying:
def roundSmart[A](num: A)(implicit numeric: Numeric[A]) = num match {
case num if num < 1 => numeric.toDouble(num)
case _ => numeric.toInt(num)
}
Which throws this error:
value < is not a member of type parameter A
Of course the parameters need to accept a range of parameter types within the function signature as it may be taking integers or doubles so this has added a further complexity.
I've taken the conditional statement on the first case from this answer -
Using comparison operators in Scala's pattern matching system and am eager to use a Functional Programming approach. Perhaps there is also some in-built scala function like Math.round() that could help to round the second condition rather than remove any decimals. Thanks!
TL;DR : every numeric methods you'll need are inside numeric
The error is self-explanatory: your type A (which is generic) does not have a < method.
However, what you have is a typeclass with all numeric methods in it, so you should probably import them:
import numeric._
This imports (among other things) implicit conversion to OrderingOps, which has the desired method. But this comparison cannot work, since 1 is not an A, it's an Int!
The solution is simply to use fromIntof numeric.
While we're at it, you will have unexpected results for input such as -234.2e123... You'd better do your test on the absolute value of your number (abs is also a method of numeric).
Also, if you want to do a simple test, there is no need to use pattern matching, a if else statement is enough
def roundSmart[A](num: A)(implicit numeric: Numeric[A]) = {
import numeric._
if (abs(num) < fromInt(1)) toDouble(num) else toInt(num)
}
I went to the effort to create myself a class whereby I have an equals method that defines an equivalence relation for which the partition sets don't have size == 1.
The class takes an absolute path and a root (also a path), these "relative paths" are equivalent if their path relative to their roots are the same. I have two sets with these in and I have ensured that all the elements in each individual set have the same root. So, according to my logic there should be one or zero element(s() in the second set that == any element in the first set.
But now I realize that I don't have the nice O(1) lookup I wanted as the Set.contains() method only returns a boolean, not the element it found!! Is there a method or collection I'm not aware of that will give me the O(1) behaviour I'm looking for (i.e. an O(1) lookup on equals, returning the equal element.)
Redefining equality to mean something else than equality of all elements is almost always a bad idea. Scala sets assume that if two things are equal, they are interchangeable. This is not the case in your approach.
I think you will have to use a Map[T, T] instead of a Set[T] to do what you want.
This must surely have been asked before, but if so, I'm not able to find it.
There is a hole in the API here, as far as I can see.
Perhaps hope somebody can do better, but the best workaround I can find is:
def lookup[T](s: Set[T], x: T): Option[T] =
s.intersect(Set(x)).headOption
Let's take it for a spin. First define a case class that carries extra information that doesn't affect equality:
scala> case class C(x: Int)(val y: Int)
defined class C
scala> C(3)(5) == C(3)(6)
res4: Boolean = true
Now let's try a test case:
scala> val s = Set(C(3)(5), C(8)(2), C(7)(6))
s: scala.collection.immutable.Set[C] = Set(C(3), C(8), C(7))
scala> lookup(s, C(8)(99)).map(_.y)
res6: Option[Int] = Some(2)
Looks good.
As for whether it's O(1), it appears to me from perusing https://github.com/scala/scala/blob/2.11.x/src/library/scala/collection/immutable/HashSet.scala that it is.
I was always figuring implicit conversions over multiple levels is not possible in scala (unless you define view bounds: http://docs.scala-lang.org/tutorials/FAQ/context-and-view-bounds.html)
But it seems that there is a flaw in the type system or an inconsistency.
Following an example (adapted from How can I chain implicits in Scala?)
class A(val n: Double){
def total = n + 10
}
object T1{
implicit def toA(n: Double): A = new A(n)
val i : Int = 5
println(i.total) //Why does this work?
println(5.2.total)
}
I do not really understand why the implicit conversion from Int -> Double -> A works. Can someone please explain the reasons? Thanks
It happens via a different mechanism, unique to the numeric types, called numeric widening.
SLS 6.26.1 Value Conversions says:
The following five implicit conversions can be applied to an expression e which has some value type T and which is type-checked with some expected type pt.
Static Overloading Resolution
Type Instantiation
Numeric Widening
Numeric Literal Narrowing
Value Discarding
View Application
Dynamic Member Selection
(Okay, that's more than five....not sure why :)
The one of interest is numeric widening:
If e has a primitive number type which weakly conforms to the expected type, it is widened to the expected type using one of the numeric conversion methods toShort, toChar, toInt, toLong, toFloat, toDouble defined here.
3.5.16 Weak Conformance says
In some situations Scala uses a more general conformance relation. A type S weakly conforms to a type T, written S<:wT, if S<:T or both S and T are primitive number types and S precedes T in the following ordering.
Byte <:w Short
Short <:w Int
Char <:w Int
Int <:w Long
Long <:w Float
Float <:w Double
So println(i.total) becomes println(i.total.toFloat) because Int <:w <: Long <: Float.
Java (and C# and many other languages) have numeric widening, and Scala decided to keep it.
Note that the reverse does not work: a Float cannot be implicitly converted to Int via this way, since magnitude could be lost; it's not a "widening".
You can add -Ywarn-numeric-widen and get a warning when this happens.
As Gabor already commented, this is due to numeric widening. If you run with the -print option, you will see that a .toDouble is appended to the i, which then allows it to use the toA implicit. You can run scalac with the warn-numeric-widen and this will at least give you the following:
<console>:14: warning: implicit numeric widening
println(i.total) //Why does this work?
^
The square of the hypotenuse of a right triangle is equal to the sum of the squares on the other two sides.
This is Pythagoras's Theorem. A function to calculate the hypotenuse based on the length "a" and "b" of it's sides would return sqrt(a * a + b * b).
The question is, how would you define such a function in Scala in such a way that it could be used with any type implementing the appropriate methods?
For context, imagine a whole library of math theorems you want to use with Int, Double, Int-Rational, Double-Rational, BigInt or BigInt-Rational types depending on what you are doing, and the speed, precision, accuracy and range requirements.
This only works on Scala 2.8, but it does work:
scala> def pythagoras[T](a: T, b: T, sqrt: T => T)(implicit n: Numeric[T]) = {
| import n.mkNumericOps
| sqrt(a*a + b*b)
| }
pythagoras: [T](a: T,b: T,sqrt: (T) => T)(implicit n: Numeric[T])T
scala> def intSqrt(n: Int) = Math.sqrt(n).toInt
intSqrt: (n: Int)Int
scala> pythagoras(3,4, intSqrt)
res0: Int = 5
More generally speaking, the trait Numeric is effectively a reference on how to solve this type of problem. See also Ordering.
The most obvious way:
type Num = {
def +(a: Num): Num
def *(a: Num): Num
}
def pyth[A <: Num](a: A, b: A)(sqrt: A=>A) = sqrt(a * a + b * b)
// usage
pyth(3, 4)(Math.sqrt)
This is horrible for many reasons. First, we have the problem of the recursive type, Num. This is only allowed if you compile this code with the -Xrecursive option set to some integer value (5 is probably more than sufficient for numbers). Second, the type Num is structural, which means that any usage of the members it defines will be compiled into corresponding reflective invocations. Putting it mildly, this version of pyth is obscenely inefficient, running on the order of several hundred thousand times slower than a conventional implementation. There's no way around the structural type though if you want to define pyth for any type which defines +, * and for which there exists a sqrt function.
Finally, we come to the most fundamental issue: it's over-complicated. Why bother implementing the function in this way? Practically speaking, the only types it will ever need to apply to are real Scala numbers. Thus, it's easiest just to do the following:
def pyth(a: Double, b: Double) = Math.sqrt(a * a + b * b)
All problems solved! This function is usable on values of type Double, Int, Float, even odd ones like Short thanks to the marvels of implicit conversion. While it is true that this function is technically less flexible than our structurally-typed version, it is vastly more efficient and eminently more readable. We may have lost the ability to calculate the Pythagrean theorem for unforeseen types defining + and *, but I don't think you're going to miss that ability.
Some thoughts on Daniel's answer:
I've experimented to generalize Numeric to Real, which would be more appropriate for this function to provide the sqrt function. This would result in:
def pythagoras[T](a: T, b: T)(implicit n: Real[T]) = {
import n.mkNumericOps
(a*a + b*b).sqrt
}
It is tricky, but possible, to use literal numbers in such generic functions.
def pythagoras[T](a: T, b: T)(sqrt: (T => T))(implicit n: Numeric[T]) = {
import n.mkNumericOps
implicit val fromInt = n.fromInt _
//1 * sqrt(a*a + b*b) Not Possible!
sqrt(a*a + b*b) * 1 // Possible
}
Type inference works better if the sqrt is passed in a second parameter list.
Parameters a and b would be passed as Objects, but #specialized could fix this. Unfortuantely there will still be some overhead in the math operations.
You can almost do without the import of mkNumericOps. I got frustratringly close!
There is a method in java.lang.Math:
public static double hypot (double x, double y)
for which the javadocs asserts:
Returns sqrt(x2 +y2) without intermediate overflow or underflow.
looking into src.zip, Math.hypot uses StrictMath, which is a native Method:
public static native double hypot(double x, double y);