I have a type declaration somewhat similar to this one:
type AwesomeType[F[_], X, Y] =
Foo[F] ?=>
Bar[F, X] ?=>
Baz[F, X] ?=>
Waffle[X] ?=>
F[Y]
when I run scalafmt with align.preset = more, it attempts to squeeze this chain of operators into a single line, and emits something like
type AwesomeType[F[_], X, Y] = Foo[F] ?=> Bar[F, X] ?=> Baz[
F,
X
] ?=> Waffle[X] ?=> F[Y]
Could anyone suggest a configuration that can cope with long chains of ?=> infix operators?
In case that's relevant:
in .scalafmt.conf:
version = 3.6.1
runner.dialect = scala3
in build/plugins.sbt:
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6")
Related
With the following code,
val x: ({type X[Y] = Function1[Y, Unit]})#X = (y: Int) =>println(y)
It successfully compiles, but how could I use it? When I call it with x(1)
An compiling occurs that complains Type mismatch, Y expected: Y accutal: Int
You can't have a value of a type like ({type X[Y] = Function1[Y, Unit]})#X, just as you can't have a value of type Option or Function1. The only thing you can do with it is to apply it to a parameter, or to use it as a type argument for another type/method, which will eventually apply it to some parameters.
Given the following example code:
trait Gen[T, +R] {
def follow[K](gen: Gen[R, K]): Gen[T, K]
def i: T
def j: R
}
case class GenImpl[T, R](i: T, j: R) extends Gen[T, R] {
override def follow[K](gen: Gen[R, K]): Gen[T, K] = {
GenImpl[T, K](this.i, gen.j)
}
}
The compiler will give the following error:
Error:(9, 17) covariant type R occurs in invariant position in type Gen[R,K] of value gen
def follow[K](gen: Gen[R, K]): Gen[T, K]
^
however, this code cannot possibly fail a type validation in runtime. The covariant of R simply means if:
R1 <: R, R2 <: R
Then:
Gen[T, R1] <:< Gen[T, R]
So a Gen[R, K] can be a parameter of .follow() of both Gen[T, R] and Gen[T, R1]. But Gen[R1, K] can only be a parameter of .follow() of Gen[T, R1], if applied on Gen[T, R2] or Gen[T, R] it will trigger a compilation error. There is no need to set R or R1 in Gen[R/R1, K] to be contravariant to do its job.
I can't see a case that can pass compilation and fail in runtime. What do you think? Is the compiler throwing a false alarm?
Suppose we have
class R0
class R1 extends R0
class T0
Then any instance of Gen[T0, R0] must offer the following service:
def follow[K](gen : Gen[R0, K]) : Gen[T0,K]
The variance annotation claims that Gen[T0, R1] <:< Gen[T0, R0]. So it must be substitutable and offer the same service. But Gen[T0, R1] actually offers the following service:
def follow[K](gen: Gen[R1, K]) : Gen[T0,K]
Suppose I had code like this:
def doFollow[K]( g : Gen[T0, R0], h : Gen[R0, K] ) : Gen[T0,K] = {
g.follow( h )
}
Cool. Let's suppose I have some instances, constructed however:
val g0 : Gen[T0, R0] = ???
val h0 : Gen[R0, String] = ???
val g1 : Gen[T0, R1] = ???
I call doFollow[String]( g0 , h0 ) and everything works great, I get a result.
g1, I have claimed in my variance annotation, is substitutable for g0. So now I try doFollow[String]( g1 , h0 ). Oops. Then I must execute, in the body of the function,
g1.follow[String]( h0 )
but g1 only knows how to follow a Gen[R1, String]. h0 is a Gen[R0, String]. It is not true that Gen[R0, String] <:< Gen[R1, String], since the first parameter is declared invariant (it would have to be contravariant). So h0 is not an acceptable argument to g1's follow method, while it is an acceptable argument to g0's follow method. Things of g1's type, Gen[T0, R1], are not in fact substitutable for things of g0's type Gen[T0, R0].
But your variance annotation requires that Gen[T0, R1] objects can be substitutable for Gen[T0, R0]s. They cannot, and the compiler correctly called you on it.
I have the following code:
class A[+X] {
def printY[Y >: X](y: Y) = println(y)
}
class F
class G extends F
val f = new F
val g = new G
val a = new A[F]
a.printY(g)
I expect a compilation error in a.printY(g) as g has type G which is not a supertype of F. But in class A I indicated that printY method only accepts supertype of A's type paramter which is F in my example.
Why it works correctly?
Because g is also an instance of F. Therefore, Y is inferred as F, which is a supertype of F. I.e.:
a.printY[F](g)
However, this wouldn't compile:
a.printY[G](g)
Note: if you want a.printY(g) not to compile you need to rewrite the method:
def printY[Y](y: Y)(implicit ev: X <:< Y) = println(y)
This way the compiler infers the type parameter to be G and then checks whether it's a supertype of F instead of looking for a supertype of F which also happens to be an acceptable type for g.
Just try to explain why it works from another two angles.
First, as you know the upper bound is reflexive, for Y >: X, type X or subtype of Y is acceptable. so when you define val a = new A[F], printY will be like:
def printY[Y >: F](y: Y) = println(y)
when you invoke a.printY(g), printY's type parameter will be inferred as G, which is also a type of F.
Second, for def printY[Y >: F](y: Y) = println(y), when you pass an instance I of type Y, compiler will try to find the common parent of I and F and make the resultant type as the type parameter of printY, so you can even pass value of String, Int to printY.
a.printY[Any]("xxx")
a.printY[Any](3)
I am trying to write a function in Scala that will compute the partial derivative of a function with arbitrary many variables. For example
One Variable(regular derivative):
def partialDerivative(f: Double => Double)(x: Double) = { (f(x+0.001)-f(x))/0.001 }
Two Variables:
def partialDerivative(c: Char, f: (Double, Double) => Double)(x: Double)(y: Double) = {
if (c == 'x') (f(x+0.0001, y)-f(x, y))/0.0001
else if (c == 'y') (f(x, y+0.0001)-f(x, y))/0.0001
}
I am wondering if there is a way to write partialDerivative where the number of variables in f do not need to be known in advance.
I read some blog posts about varargs but can't seem to come up with the correct signature.
Here is what I tried.
def func(f: (Double*) => Double)(n: Double*)
but this doesn't seem to be correct. Thanks for any help on this.
Double* means f accepts an arbitrary Seq of Doubles, which is not correct.
The only way I can think of to write something like this is using shapeless Sized. You will need more implicits than this, and possibly some type-level equality implicits as well; type-level programming in scala is quite complex and I don't have the time to debug this properly, but it should give you some idea:
def partialDerivative[N <: Nat, I <: Nat](f: Sized[Seq[Double], N] => Double)(i: I, xs: Sized[Seq[Double], N])(implicit diff: Diff[I, N]) = {
val (before, atAndAfter) = xs.splitAt(i)
val incrementedAtAndAfter = (atAndAfter.head + 0.0001) +: atAndAfter.tail
val incremented = before ++ incrementedAtAndAfter
(f(incremeted) - f(xs)) / 0.0001
}
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))
^