Trying to implement, in Scala, the following Haskell function (from Learn You a Haskell...) so that it works with Int, Double, etc.
doubleUs x y = x * 2 + y * 2
Note that this is similar to Scala: How to define "generic" function parameters?
Here's my attempt and error. Can someone explain what's happening and offer a solution. Thanks.
scala> def doubleUs[A](x:A,y:A)(implicit numeric: Numeric[A]): A = numeric.plus(numeric.times(x,2),numeric.times(y,2))
<console>:34: error: type mismatch;
found : Int(2)
required: A
def doubleUs[A](x:A,y:A)(implicit numeric: Numeric[A]): A = numeric.plus(numeric.times(x,2),numeric.times(y,2))
In addition to what #Dylan said, you can make it look a little less tedious by importing into scope the contents of Numeric implicit as shown below:
scala> def doubleUs[N](x: N, y: N)(implicit ev: Numeric[N]) = {
| import ev._
| x * fromInt(2) + y * fromInt(2)
| }
doubleUs: [N](x: N, y: N)(implicit ev: Numeric[N])N
scala> doubleUs(3, 4)
res9: Int = 14
scala> doubleUs(8.9, 1.2)
res10: Double = 20.2
You are using the Int literal 2 but scala is expecting the Numeric type A.
The Scala Numeric API has a utility function- def fromInt(x:Int): T. This is what you want to use, so replace your usage of 2 with numeric.fromInt(2)
def doubleUs[A](x:A,y:A)(implicit numeric: Numeric[A]): A =
numeric.plus (numeric.times (x, numeric.fromInt (2)), numeric.times (y, numeric.fromInt (2)))
Also, since a Numeric instance defines an implicit conversion to an Ops, you can import numeric._ and then say x * fromInt(2) + y * fromInt(2).
You need some implicits in scope:
def doubleUs[A](x: A, y: A)(implicit num: Numeric[A]) = {
import num._
implicit def fromInt(i: Int) = num.fromInt(i)
x * 2 + y * 2
}
Dylan essentially answered, but for what it's worth, let me suggest to use the context bound syntax instead of the implicit argument (both are equivalent, and the former is automatically rewritten into the latter by the compiler).
def doubleUs[A : Numeric](x : A, y : A) : A = {
val num = implicitly[Numeric[A]]
import num.{plus,times,fromInt}
plus(times(x, fromInt(2)), times(y, fromInt(2)))
}
Related
I am trying to use the 2nd approach ("Module Abstractions") from the "Opaque Types" chapter of the Scala3 book. The code is intended to show how one can make Scala use a logarithmic number representation.
The problem is that I do not see how the code from the book may be used. For me, it just does not work.
trait Logarithms:
type Logarithm
// operations on Logarithm
def add(x: Logarithm, y: Logarithm): Logarithm
def mul(x: Logarithm, y: Logarithm): Logarithm
// functions to convert between Double and Logarithm
def make(d: Double): Logarithm
def extract(x: Logarithm): Double
// extension methods to use `add` and `mul` as "methods" on Logarithm
extension (x: Logarithm)
def toDouble: Double = extract(x)
def + (y: Logarithm): Logarithm = add(x, y)
def * (y: Logarithm): Logarithm = mul(x, y)
// I added
def myToDouble: Double = extract(x)
object LogarithmsImpl extends Logarithms:
type Logarithm = Double
// operations on Logarithm
def add(x: Logarithm, y: Logarithm): Logarithm = make(x.toDouble + y.toDouble)
def mul(x: Logarithm, y: Logarithm): Logarithm = x + y
// functions to convert between Double and Logarithm
def make(d: Double): Logarithm = math.log(d)
def extract(x: Logarithm): Double = math.exp(x)
// I added
object Logarithms:
def apply(d: Double) = LogarithmsImpl.make(d)
The book says:
However, this abstraction is slightly leaky. We have to make sure to
only ever program against the abstract interface Logarithms and never
directly use LogarithmsImpl. Directly using LogarithmsImpl would make
the equality Logarithm = Double visible for the user, who might
accidentally use a Double where a logarithmic double is expected.
And now I try to use it:
$ ~/Downloads/scala3-3.1.3/bin/scala
Welcome to Scala 3.1.3 (14.0.1, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
scala> :load my/scala/logarithms1.scala
// defined trait Logarithms
// defined object LogarithmsImpl
// defined object Logarithms
scala> import Logarithms.*
scala> Logarithms(4)
val res0: LogarithmsImpl.Logarithm = 1.3862943611198906
scala> Logarithms(2)
val res1: LogarithmsImpl.Logarithm = 0.6931471805599453
scala> Logarithms(4).toDouble
val res2: Double = 1.3862943611198906
scala> Logarithms(4).myToDouble
-- [E008] Not Found Error: ----------------------------------------------------------------------------------------------------
1 |Logarithms(4).myToDouble
|^^^^^^^^^^^^^^^^^^^^^^^^
|value myToDouble is not a member of LogarithmsImpl.Logarithm, but could be made available as an extension method.
|
|The following import might fix the problem:
|
| import LogarithmsImpl.myToDouble
|
1 error found
In fact, importing LogarithmsImpl does not help much:
scala> import LogarithmsImpl.*
scala> import Logarithms.*
scala> val ll: Logarithm = make(4.0)
val ll: LogarithmsImpl.Logarithm = 1.3862943611198906
scala> val lll: Logarithm = make(2.0)
val lll: LogarithmsImpl.Logarithm = 0.6931471805599453
scala> lll+ll
val res0: Double = 2.0794415416798357
scala> extract(lll+ll)
val res1: Double = 7.999999999999998
The last line shows that the addition was the traditional floating-point addition rather than the override from the extension.
What am I missing?
UPD One more problem in the book's code: the line
def add(x: Logarithm, y: Logarithm): Logarithm = make(x.toDouble + y.toDouble)
should be
def add(x: Logarithm, y: Logarithm): Logarithm = make(x.myToDouble + y.myToDouble)
or, even better:
def add(x: Logarithm, y: Logarithm): Logarithm = x + math.log1p(math.exp(y-x))
UPD2 and it looks like the trait and the objects are not companions, a trait is not a class, only classes may be companions.
The most reasonable way of using this abstraction (that I can see) is like so:
#main
def main = {
val L = LogarithmsImpl
doStuffWithLogarithm(L)
}
def doStuffWithLogarithm(L: Logarithms): Double = {
import L.*
val a = L.make(1)
val b = L.make(2)
a.myToDouble
}
The gist of it is that you have to pass some instance of Logarithms and use it to access all methods so that the type alias equality doesn't leak.
scastie: https://scastie.scala-lang.org/KacperFKorban/4bnxghkMSzaPqn4vvy19QA/1
That's why it's not a great pattern. And why opaque types are useful.
I am trying to implement a method that can accept as input either a Breeze Vector or a Breeze Matrix. Something like
private def updateExponentialMovingAverage[T](tau: Double, initTheta: T, theta: T): T = {
tau * theta + (1 - tau) * initTheta
}
However this raises an issue with overloading and I cannot find an appropriate type to restrict T. Do you have any suggestions?
Breezes uses type classes for most of these kinds of things. The easiest thing to do is to use the VectorSpace type class, though unfortunately for DenseMatrices the VectorSpace typeclass is gated behind another import, which I regret.
import breeze.linalg._
import breeze.math._
import breeze.linalg.DenseMatrix.FrobeniusInnerProductDenseMatrixSpace.space
def updateExponentialMovingAverage[T](tau: Double, initTheta: T, theta: T)(implicit vs: VectorSpace[T, Double]): T = {
import vs._
theta * tau + initTheta * (1 - tau)
}
scala> val dv = DenseVector.rand(3)
val dv: breeze.linalg.DenseVector[Double] = DenseVector(0.21025028035007942, 0.6257503866073217, 0.8304592391242225)
scala> updateExponentialMovingAverage(0.8, dv, dv)
val res0: breeze.linalg.DenseVector[Double] = DenseVector(0.21025028035007942, 0.6257503866073217, 0.8304592391242225)
scala> val dm = DenseMatrix.rand(3, 3)
val dm: breeze.linalg.DenseMatrix[Double] = 0.6848513069340505 0.8995141354384266 0.3889904836678608
0.4554398871938874 0.03297082723969558 0.6708501327709948
0.4456539828672945 0.04289112062985678 0.9679002485942578
updateExponentialMovingAverage(0.8, dm, dm)
val res1: breeze.linalg.DenseMatrix[Double] = 0.6848513069340505 0.8995141354384266 0.3889904836678608
0.4554398871938874 0.03297082723969558 0.6708501327709948
0.4456539828672945 0.04289112062985678 0.9679002485942578
Currently I write some ugly code like
def div(dividend: Int, divisor: Int) = {
val q = dividend / divisor
val mod = dividend % divisor
(q, mod)
}
Is it specified in standard library?
A bit late to the game, but since Scala 2.8 this works:
import scala.math.Integral.Implicits._
val (quotient, remainder) = 5 /% 2
No (except for BigInt, as mentioned in other answers), but you can add it:
implicit class QuotRem[T: Integral](x: T) {
def /%(y: T) = (x / y, x % y)
}
will work for all integral types. You can improve performance by making separate classes for each type such as
implicit class QuotRemInt(x: Int) extends AnyVal {
def /%(y: Int) = (x / y, x % y)
}
In BigInt, note /% operation which delivers a pair with the division and the reminder (see API). Note for instance
scala> BigInt(3) /% BigInt(2)
(scala.math.BigInt, scala.math.BigInt) = (1,1)
scala> BigInt(3) /% 2
(scala.math.BigInt, scala.math.BigInt) = (1,1)
where the second example involves an implicit conversion from Int to BigInt.
BigInt does it
def /%(that: BigInt): (BigInt, BigInt)
Division and Remainder - returns tuple containing the result of divideToIntegralValue and the remainder.
i tried
type ?[_] = Option[_]
def f(x: ?[Int]) = for (y <- x) yield y
(but i don't know what i am doing.)
insofar as types are just objects, i should be able to define a postix operator (i.e. zero arity method) for use in type signatures (i think). it might need a space like
def f(x: Int ?) = for (y <- x) yield y
scala makes it easy to use the Option type with matching and polymorphism, avoid null. but, most classes are (nullable) vars and java often returns vars. using classes and calling java are two of scala's selling points. an easy-to-write and easy-to-read syntax would support Options even more strongly.
what are all the things that scala does with "?" that make its parsing special.
ideally, one could write
def f(x: Int?) = for (y <- x) yield y
like other languages. can we do this in scala (without a macro)?
First, types are not objects. In fact, Scala has exactly two namespaces: values and types. They are very different things, and play by very different rules.
The postfix idea is kind of nice, actually, but it is not possible. There's an infix notation for types, though.
Now, to what you wrote:
type ?[_] = Option[_]
Each underscore has a different meaning. The underscore in ?[_] means ? is higher-kinded, but you don't care what it's type parameter is. The underscore in Option[_] means Option is an existential type. So when you write x: ?[Int], Scala will convert it to x: Option[t] { forSome type t }. This means that not only you don't get the Int, but the type parameter of Option is unknowable (you just know it exists).
However, it does compile:
scala> def f(x: ?[Int]) = for (y <- x) yield y
f: (x: ?[Int])Option[Any]
Which version of Scala did you use? 2.11? A co-worker of mine has already found some type inference regressions on 2.11, so that could be it.
The proper way to write the type alias would be this:
type ?[+A] = Option[A]
Not only we pass the type parameter along (it is a parameter, after all!), but we need to specify co-variance for it to act just Option (which is co-variant itself).
Now, as to your two questions, Scala has absolutely no special treatment of ?. And, no, you can't do this. This ? is not exactly widespread among languages either, and in all of them that support it, it is built in the language, and not something externally defined.
Besides, it's kind of a joke that, when interface with Java, typing out Option would be a problem -- not with the average identifier size in Java!
You intended to get an Option[Int] out:
scala> type ?[A] = Option[A]
defined type alias $qmark
scala> def f(x: ?[Int]) = for (y <- x) yield y + 1
f: (x: ?[Int])Option[Int]
and it does compile anyway.
You could maybe
scala> type ?[A,_] = Option[A]
defined type alias $qmark
scala> def f(x: Int ? _) = for (y <- x) yield y + 1
f: (x: ?[Int, _])Option[Int]
or similar.
scala> def f(x: Int ?_) = for (y <- x) yield y + 1
f: (x: ?[Int, _])Option[Int]
looks more postfixy.
P.S. Still curious whether variance annotation on type alias is required or merely advisable.
scala> type ?[A] = Option[A]
defined type alias $qmark
scala> trait X ; trait Y extends X ; trait Z extends X
defined trait X
defined trait Y
defined trait Z
scala> val x: ?[X] = null.asInstanceOf[?[Y]] // why is this OK?
x: ?[X] = null
scala> class C[A]
defined class C
scala> val c: C[X] = null.asInstanceOf[C[Y]] // like this is not OK
<console>:10: error: type mismatch;
found : C[Y]
required: C[X]
Note: Y <: X, but class C is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
val c: C[X] = null.asInstanceOf[C[Y]]
^
Maybe compare SI-8522 and related issues.
You might consider a renaming import. When you create a type alias you only rename a type. When you rename a symbol during import you include all referents of that name, both type and value.
To wit:
scala> import scala.{Option => ?}
import scala.{Option=>$qmark}
scala> val oi1: ?[Int] = Some(1)
oi1: Option[Int] = Some(1)
scala> def mi1(oi: ?[Int]): Int = oi.getOrElse(-1)
mi1: (oi: Option[Int])Int
scala> mi1(None)
res1: Int = -1
scala> mi1(?(1))
res2: Int = 1
Compare with this:
scala> type ?[A] = Option[A]
scala> def mi1(oi: ?[Int]): Int = oi.getOrElse(-1)
mi1: (oi: ?[Int])Int
scala> mi1(?(1))
<console>:10: error: not found: value ?
mi1(?(1))
^
I'd like to implement a "matrix dot product" in Scala in the following way:
type Real = Double
type Row = Array[Real]
type Matrix = Array[Row]
def dot[T](f: (T,T) => Real)(as: Iterable[T], bs: Iterable[T]): Real =
(for ((a, b) <- as zip bs) yield f(a, b)) sum
def rowDot(r1: Row, r2: Row) = dot(_*_)(r1, r2)
def matDot(m1: Matrix, m2: Matrix) = dot(rowDot)(m1, m2)
However, the definition of rowDot doesn't work. Scala needs explicit type annotations for the anonymous function (_*_), so instead I must write
def rowDot(r1: Row, r2: Row) = dot((x:Real, y: Real) => x*y)(r1, r2)
or
def rowDot = dot((x:Real, y: Real) => x*y) _
Is there some way to change the definition of dot so that the shorthand (_*_) can be used?
Edit: Another confusion: matDot also gives type errors in certain circumstances. It fails with Arrays of Arrays, but not with Lists of Arrays
scala> matDot(Array(Array(1.0,2.0)), Array(Array(1.0,2.0,3.0)))
<console>:27: error: type mismatch;
found : Array[Array[Double]]
required: Iterable[Iterable[Real]]
matDot(Array(Array(1.0,2.0)), Array(Array(1.0,2.0,3.0)))
^
scala> matDot(List(Array(1.0,2.0)), List(Array(1.0,2.0,3.0)))
res135: Real = 5.0
What's the difference?
specifying dot[Real] explicitly should work too.
def rowDot(r1: Row, r2: Row) = dot[Real](_*_)(r1, r2)
EDIT
replying to your edit: I think the issue is that the implicit conversion from Array to WrappedArray is not applied recursively when you have a Array[Array].
Array[Int] is not an Iterable[Int]; normally, when you assign it to a Iterable, an Array[Int] is implicitly converted to a WrappedArray[Int] (where WrappedArray is a Iterable[Int]). This is what happens when you use List[Array[Int]] (you get a List[WrappedArray[Int]] implicitly).
However, as I said, the implicit conversion is not applied recursively, so an Array[Array[Int]] is not implicitly converted to WrappedArray[WrappedArray[Int]].
Here's a REPL session that demonstrates the problem:
A List[Array[Int]] can be assigned to Iterable[Iterable[Int]] (note that Array is converted to WrappedArray)
scala> val i : Iterable[Iterable[Int]] = List(Array(1,2), Array(1,2,3))
i: Iterable[Iterable[Int]] = List(WrappedArray(1, 2), WrappedArray(1, 2, 3))
An Array[Array[Int]] does not work automatically (as you discovered)
scala> val j : Iterable[Iterable[Int]] = Array(Array(1,2), Array(1,2,3))
<console>:9: error: type mismatch;
found : Array[Array[Int]]
required: Iterable[Iterable[Int]]
val j : Iterable[Iterable[Int]] = Array(Array(1,2), Array(1,2,3))
^
However, with some hand-holding (converting manually the inner Arrays to WrappedArrays) everything works again:
scala> import scala.collection.mutable.WrappedArray
import scala.collection.mutable.WrappedArray
scala> val k : Iterable[Iterable[Int]] = Array(WrappedArray.make(Array(1,2)),
WrappedArray.make(Array(1,2,3)))
k: Iterable[Iterable[Int]] = WrappedArray(WrappedArray(1, 2), WrappedArray(1, 2,
3))
Yes - if you switch your argument lists around. Type inference on function parameters works more effectively when the function parameter is alone in the last argument list:
def dot[T](as: Iterable[T], bs: Iterable[T])(f: (T,T) => Real): Real =
(for ((a, b) <- as zip bs) yield f(a, b)) sum
def rowDot(r1: Row, r2: Row) = dot(r1, r2)(_*_)