Scala has a number of traits that you can use as type classes, for example Ordered and Numeric in the package scala.math.
I can, for example, write a generic method using Ordered like this:
def f[T <% Ordered[T]](a: T, b: T) = if (a < b) a else b
I wanted to do a similar thing with Numeric, but this doesn't work:
def g[T <% Numeric[T]](a: T, b: T) = a * b
Why is there an apparent discrepancy between Ordered and Numeric?
I know there are other ways to do this, the following will work (uses a context bound):
def g[T : Numeric](a: T, b: T) = implicitly[Numeric[T]].times(a, b)
But that looks more complicated than just being able to use * to multiply two numbers. Why does the Numeric trait not include methods like *, while Ordered does include methods like <?
I know there's also Ordering which you can use in the same way as Numeric, see also this answer:
def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)
The symbolic operators are available if you import them from the implicit Numeric[T]
def g[T : Numeric](a: T, b: T) = {
val num = implicitly[Numeric[T]]
import num._
a * b
}
This is clearly a bit unwieldy if you want to make use of just a single operator, but in non-trivial cases the overhead of the import isn't all that great.
Why are the operators not available without an explicit import? The usual considerations against making implicits visible by default apply here, perhaps more so because these operators are so widely used.
Ordered is just a few simple pimped methods that return either Int or Boolean, so no type-trickery is needed.
Numeric, on the other hand, has methods that return different types depending on the exact subclass used. So while Ordered is little more than a marker trait, Numeric is a fully-featured type class.
To get your operators back, you can use mkNumericOps (defined in Numeric) on the lhs operand.
UPDATE
Miles is quite right, mkNumericOps is implicit, so just importing that instance of Numeric will give you back all the magic...
You can reduce Miles' solution to only use 1 extra line by doing this:
Add an implicit conversion from A : Numeric to Numeric[A]#Ops
object Ops {
implicit def numeric[A : Numeric](a: A) = implicitly[Numeric[A]].mkNumericOps(a)
}
Then bring this into scope in your method
def g[T : Numeric](a: T, b: T) = {
import Ops.numeric
a * b
}
See Scala ticket 3538 for more info.
Related
I have been trying to determine how one might write a type parameter that restricts a function to types that support relational operators?
For example:
def biggerOf[A <: ???](a: A, b: A): A = { if (a > b) a else b }
Where ??? is my dilemma. Advanced type parameter bits are new to me, so asking for a little help. Thought AnyVal might be a winner but for Unit type (and Boolean which won't break, but won't work either). Thanks for any ideas.
You want to bring the Ordering typeclass into play.
import scala.math.Ordering.Implicits.infixOrderingOps
def biggerOf[A:Ordering](a: A, b: A): A = { if (a > b) a else b }
A:Ordering restricts A to types in the Ordering typeclass and infixOrderingOps enables the convenience operators (methods) such as <, >=, etc.
You can use the ordering typeclass.
def biggerOf[A : Ordering](a: A, b: A): A = {
import Ordering.Implicits._
if (a > b) a else b
}
As Luis and jwvh has suggested, you can use the Ordering typeclass but I'd like to introduce to you the typeclass pattern and using typeclasses in restricting the usage of a function in a more depth.
A typeclass allows one to be able to be flexible in its generic types whilst restricting it enough that those that do not have an instance of the typeclass may not be able to use your function.
Take this as an example, assuming that the Numerical datatypes in Scala have no operators on them, we can generalize the idea of operating on them by introducing the Num typeclass and then by specifying their behavior on the operation because these Numerical datatypes have different ways of handling algebraic operations. (e.g an Integral vs Real number)
trait Num[A] {
def add(l: A, r: A): A
def sub(l: A, r: A): A
def mul(l: A, r: A): A
def div(l: A, r: A): A
}
object NumTest {
def addThenMultiply[A](l: A, r: A)(implicit ev: Num[A]): A =
ev.mul(ev.add(l, r), r)
//then we create Num instances for numerical types
implicit val intNum = new Num[Int] { /* implementation*/ }
implicit val floatNum = new Num[Float] { /* implementation */ }
}
Now in this case, the function addThenMultiply will only work for Int and Float datatypes since they're the only ones that have a Num instance but you can add instances for other custom datatypes also depending on your need.
def weirdfunc(message: String, f: (Int, Int) => Int){
println(message + s" ${f(3,5)}")
}
I have the function as above. How do I make it so that the function f is generic for all Numeric types?
What you want is called a higher-ranked type (specifically, rank 2). Haskell has support for these types, and Scala gets a lot of its type theory ideas from Haskell, but Scala has yet to directly support this particular feature.
Now, the thing is, with a bit of black magic, we can get Scala to do what you want, but the syntax is... not pretty. In Scala, functions are always monomorphic, but you want to pass a polymorphic function around as an argument. We can't do that, but we can pass a polymorphic function-like object around that looks and behaves mostly like a function. What would this object look like?
trait NumFunc {
def apply[A : Numeric](a: A, b: A): A
}
It's just a trait that defines a polymorphic apply. Now we can define the function that you really want.
def weirdfunc(message: String, f: NumFunc) = ???
The trouble here, as I mentioned, is that the syntax is really quite atrocious. To call this, we can't just pass in a function anymore. We have to create a NumFunc and pass that in. Essentially, from a type theoretic perspective, we have to prove to the compiler that our function works for all numeric A. For instance, to call the simple weirdfunc that only takes integers and pass the addition function is very simple.
weirdfunc("Some message", (_ + _))
However, to call our "special" weirdfunc that works for all number types, we have to write this mess.
weirdfunc("Hi", new NumFunc {
override def apply[A : Numeric](a: A, b: A): A = {
import math.Numeric.Implicits._
a + b
}
})
And we can't hide that away with an implicit conversion because, as I alluded to earlier, functions are monomorphic, so any conversion coming out a function type is going to be monomorphic.
Bottom line. Is it possible? Yes. Is it worth the costs in terms of readability and usability? Probably not.
Scala has a typeclass for this, so it's quite easy to achieve using a context bound and the standard lib.
def weirdfunc[T: Numeric](message: String, x: T, y: T, f: (T, T) => T) {
println(message + s" ${f(x, y)}")
}
def test[T](a: T, b: T)(implicit ev: Numeric[T]): T = ev.plus(a, b)
weirdFunc[Int]("The sum is ", 3, 5, test)
// The sum is 8
Sorry cktang you cannot generify this. The caller gets to set the generic parameter.. not the called function.. just like the caller passes function parameters.
However you can use currying so that you pass the 'f' of type Int once, and then pass different Int pairs. Then you may pass 'f' of type Double, and pass different Double pairs.
def weirdfunc[A](message: String, f: (A, A) => A)(x: A, y: A){
println(message + s" ${f(x, y)}")
}
def g(x: Int, y: Int): Int = x * y
val wierdfuncWithF = weirdfunc("hello", g) _
wierdfuncWithF(3, 5)
wierdfuncWithF(2, 3)
In particular what you want cannot be done as it will break generics rules.
I am trying to write a generic weighted average function.
I want to relax the requirements on the values and the weights being of the same type. ie, I want to support sequences of say: (value:Float,weight:Int) and (value:Int,weight:Float) arguments and not just: (value:Int,weight:Int)
To do so, I first need to implement a function that takes two generic numerical values and returns their product.
def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) : ??? = {...}
Writing the signature and thinking about the return type, made me realise that I need to define some sort of hierarchy for Numerics to determine the return type. ie x:Float*y:Int=z:Float, x:Float*y:Double=z:Double.
Now, Numeric class defines operations plus, times, etc. only for arguments of the same type. I think I would need to implement a type:
class NumericConverter[Numeirc[A],Numeric[B]]{
type BiggerType=???
}
so that I can write my times function as:
def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) :
NumericConverter[Numeirc[A],Numeric[B]].BiggerType= {...}
and convert the "smaller type" to the "bigger one" and feed it to times().
Am I on the right track? How would I "implement" the BiggerType?
clearly I can't do something like:
type myType = if(...) Int else Float
as that is evaluated dynamically, so it worn't work.
I understand that I might be able to do this Using Scalaz, etc. but this is an academic exercise and I want to understand how to write a function that statically returns a type based on the argument types.
Feel free to let me know if there is a whole easier way of doing this.
update:
this is what I came up with it.
abstract class NumericsConvert[A: Numeric,B: Numeric]{
def AisBiggerThanB: Boolean
def timesA=new PartialFunction[(A,B), A] {
override def isDefinedAt(x: (A, B)): Boolean = AisBiggerThanB
override def apply(x: (A, B)): A = implicitly[Numeric[A]].times(x._1, x._2.asInstanceOf[A])
}
def timesB=new PartialFunction[(A,B), B] {
override def isDefinedAt(x: (A, B)): Boolean = !AisBiggerThanB
override def apply(x: (A, B)): B = implicitly[Numeric[B]].times(x._1.asInstanceOf[B], x._2)
}
def times: PartialFunction[(A, B), Any] = timesA orElse timesB
}
def times[A: Numeric, B: Numeric](x: B, y: A)= implicitly[NumericsConvert[A,B]].times(x,y)
which is silly as I will have to create implicits for both
IntDouble extends NumericsConvert[Int,Double]
and
DoubleInt extends NumericsConvert[Double,Int]
not to mention that the return type of times is now Any, but regardless, I am getting errors for my times functions. I thought I would add it here in case it might help with arriving at a solution. so side question: how I can pass context bound types of one class/function to another like I am trying to do in times.
I think you're making this harder than it needs to be.
You need "evidence" that both parameters are Numeric. With that established let the evidence do the work. Scala will employ numeric widening so that the result is the more general of the two received types.
def mult[T](a: T, b: T)(implicit ev:Numeric[T]): T =
ev.times(a,b)
If you want to get a little fancier you can pull in the required implicits. Then it's a little easier to read and understand.
def mult[T: Numeric](a: T, b: T): T = {
import Numeric.Implicits._
a * b
}
Proof:
mult(2.3f , 7) //res0: Float = 16.1
mult(8, 2.1) //res1: Double = 16.8
mult(3, 2) //res2: Int = 6
For more on generic types and numeric widening, this question, and its answer, are worth studying.
Sorry, I have hard times figuring out a relevant title for my problem.
I want to model the following behavior: I designed a "language" with expressions that encapsulate standard Scala types. Expressions can be either variables or sequences of expressions. In the following, A can be a standard Scala type (namely Boolean, Int, Double). I also want to implement a method to replace expressions by other in expressions (particularly in sequences). I tried some code which I cannot manage to compile. I placed quotation marks when I do not really know what type to put but all the this is probably messy. I have special trouble with the Sequence thing, due to its recursive nature.
sealed trait Expression[A] {
def replace[B](a: Expression[B], b: Expression[B]): Expression[?]
}
trait Variable[A] extends Expression[A] {
def replace[B](a: Expression[B], b: Expression[B]) =
if (a == this) b else this
}
case class Sequence[A <: Expression[B]](values: Seq[A]) extends Expression[A] {
def replace[B](a: Expression[B], b: Expression[B]) =
if (a == this) b
else Sequence(values.map(_.replace(a, b)))
}
I assume of course that sequences are acyclic (a sequence cannot contain itself) as it would trigger an infinite recursion. These are used to implement n-ary matrices.
Thanks for your help.
It looks like you ran into one of those corner cases where Scala does not have an elegant solution.
What you need in the place of Expression[?] as the return type is actually a type that represents "this type", being the type that the trait is actually mixed into. There is no shorthand in Scala that lets you express this in a simple way, and you cannot use this.type either, as that is too specific and can only be used when you really always return this.
The solution usually quickly introduces mind-bending boilerplate. The Scala collections for example suffer from the same issue, traits like MapLike need to encode similar things.
I tried to quickly modify your sample to encode such a type. I made sure it compiles, but I did not run it:
sealed trait Expression[A, ThisType <: Expression[A, ThisType]] {
def replace[B,C <: Expression[B,C]](a: Expression[B,C], b: Expression[B,C]): ThisType
}
trait Variable[A] extends Expression[A, Variable[A]] {
def replace[B,C <: Expression[B,C]](a: Expression[B,C], b: Expression[B,C]) =
if (a == this) b.asInstanceOf[Variable[A]] else this
}
case class Sequence[A <: Expression[_,A]](values: Seq[A]) extends Expression[A, Sequence[A]] {
def replace[B,C <: Expression[B,C]](a: Expression[B,C], b: Expression[B,C]) =
if (a == this) b.asInstanceOf[Sequence[A]]
else Sequence(values.map(_.replace(a, b)))
}
It even has to use a cast, which usually is a smell on its own, but I'm not sure there is a way to avoid it in this case. At least it is safe, we know it has to have the right type, just the compiler does not know it. :-)
Usually in situations like this there is a required relationship between A and B. E.g., consider what happens when you add an element to a (hypothetical and highly simplified) sequence type:
class Sequence[+A] {
def +: [B >: A](b: B): Sequence[B] = {
/* Build the new sequence with b at the beginning and this sequence's elments after */
}
}
So in your case (if this pattern applies for you), signature in Expression[A] would be:
def replace[B >: A](a: Expression[B], b: Expression[B]): Expression[B]
Thank you for your answers. I ended simplifying up my problem to obtain a simpler solution. I simply "flattened" the type parameter of sequences:
case class Sequence[A] (values: Seq[Expression[A]]) extends Expression[A] {
def replace[B <: A](a: Expression[A], b: Expression[B]) {
// (Code in initial question)
}
}
A in Expression now means that Expression is either a variable of type A, a sequence of variables of type A, a sequence of sequence of variables of type A…
I lose expressiveness here, but gain in usability. Having two parameters for Expression was getting too complicated, and broke Java interoperability. Maybe I will try to improve this on later.
Okay, fair warning: this is a follow-up to my ridiculous question from last week. Although I think this question isn't as ridiculous. Anyway, here goes:
Previous ridiculous question:
Assume I have some base trait T with subclasses A, B and C, I can declare a collection Seq[T] for example, that can contain values of type A, B and C. Making the subtyping more explicit, let's use the Seq[_ <: T] type bound syntax.
Now instead assume I have a typeclass TC[_] with members A, B and C (where "member" means the compiler can find some TC[A], etc. in implicit scope). Similar to above, I want to declare a collection of type Seq[_ : TC], using context bound syntax.
This isn't legal Scala, and attempting to emulate may make you feel like a bad person. Remember that context bound syntax (when used correctly!) desugars into an implicit parameter list for the class or method being defined, which doesn't make any sense here.
New premise:
So let's assume that typeclass instances (i.e. implicit values) are out of the question, and instead we need to use implicit conversions in this case. I have some type V (the "v" is supposed to stand for "view," fwiw), and implicit conversions in scope A => V, B => V and C => V. Now I can populate a Seq[V], despite A, B and C being otherwise unrelated.
But what if I want a collection of things that are implicitly convertible both to views V1 and V2? I can't say Seq[V1 with V2] because my implicit conversions don't magically aggregate that way.
Intersection of implicit conversions?
I solved my problem like this:
// a sort of product or intersection, basically identical to Tuple2
final class &[A, B](val a: A, val b: B)
// implicit conversions from the product to its member types
implicit def productToA[A, B](ab: A & B): A = ab.a
implicit def productToB[A, B](ab: A & B): B = ab.b
// implicit conversion from A to (V1 & V2)
implicit def viewsToProduct[A, V1, V2](a: A)(implicit v1: A => V1, v2: A => V2) =
new &(v1(a), v2(a))
Now I can write Seq[V1 & V2] like a boss. For example:
trait Foo { def foo: String }
trait Bar { def bar: String }
implicit def stringFoo(a: String) = new Foo { def foo = a + " sf" }
implicit def stringBar(a: String) = new Bar { def bar = a + " sb" }
implicit def intFoo(a: Int) = new Foo { def foo = a.toString + " if" }
implicit def intBar(a: Int) = new Bar { def bar = a.toString + " ib" }
val s1 = Seq[Foo & Bar]("hoho", 1)
val s2 = s1 flatMap (ab => Seq(ab.foo, ab.bar))
// equal to Seq("hoho sf", "hoho sb", "1 if", "1 ib")
The implicit conversions from String and Int to type Foo & Bar occur when the sequence is populated, and then the implicit conversions from Foo & Bar to Foo and Bar occur when calling foobar.foo and foobar.bar.
The current ridiculous question(s):
Has anybody implemented this pattern anywhere before, or am I the first idiot to do it?
Is there a much simpler way of doing this that I've blindly missed?
If not, then how would I implement more general plumbing, such that I can write Seq[Foo & Bar & Baz]? This seems like a job for HList...
Extra mega combo bonus: in implementing the more general plumbing, can I constrain the types to be unique? For example, I'd like to prohibit Seq[Foo & Foo].
The appendix of fails:
My latest attempt (gist). Not terrible, but there are two things I dislike there:
The Seq[All[A :: B :: C :: HNil]] syntax (I want the HList stuff to be opaque, and prefer Seq[A & B & C])
The explicit type annotation (abc[A].a) required for conversion. It seems like you can either have type inference or implicit conversions, but not both... I couldn't figure out how to avoid it, anyhow.
I can give a partial answer for the point 4. This can be obtained by applying a technique such as :
http://vpatryshev.blogspot.com/2012/03/miles-sabins-type-negation-in-practice.html