Did you mean this perhaps?
Sorry, yes. I should have double-checked his example instead of relying on my memory. Apologies.
Did you mean this perhaps?
Sorry, yes. I should have double-checked his example instead of relying on my memory. Apologies.
@smarter: The following code doesn’t work:
@main def app = {
object Nil {
override def toString = "Nil"
}
final case class NonEmptyList[+A](head: A, tail: List[A])
type List[+A] = Nil.type | NonEmptyList[A]
inline def [A, B >: A](ls: List[A]) :: (elem: B): List[B] = NonEmptyList(elem, ls)
val x : List[Int] = Nil
val xs : List[Int] = NonEmptyList(1, NonEmptyList(2, Nil))
val ys : List[Int] = 1 :: 2 :: Nil
// Error:
// Found: (2 : Int)
// Required: List[object Nil]
println(xs)
}
Looks like an inference problem. Wdyt ?
I think you need to make that:
inline def [A, B >: A](elem: B) :: (ls: List[A]): List[B] = NonEmptyList(elem, ls)
Works. Thank you!
This was working prior to 0.24:
trait P[M: Ordering, C] {
def apply(s: (M, C)*): Seq[(M, C)]
def sort(x: Seq[(M, C)]) = apply(x.sortBy((s, _) => s): _*)
^
cannot infer type; expected type <?> is not fully defined
}
Can you open an issue for that? Also I suspect it can be minimized further (the use of a lambda whose expected type comes from a repeated parameter is probably the important part here)
This thread is specifically about improving Dotty’s type inference. For Scala 2 issues, I suggest opening an issue on github.com/scala/bug/issues
The following shapeless-style derivation of a polymorphic sequence
operation for Option
doesn’t infer a useful type in Scala 3.0.0-M1. The type is checkable but on failure the expected type is not useful.
object Blah {
trait Options[T <: Tuple] {
type Out <: Tuple
def apply(t: T): Option[Out]
}
object Options {
type Aux[T <: Tuple, O <: Tuple] = Options[T] { type Out = O }
implicit def single[H]: Aux[Option[H] *: EmptyTuple, H *: EmptyTuple] =
new Options[Option[H] *: EmptyTuple] {
type Out = H *: EmptyTuple
def apply(t: Option[H] *: EmptyTuple): Option[H *: EmptyTuple] =
t.head.map(_ *: EmptyTuple)
}
implicit def multiple[H, T <: Tuple](
implicit ev: Options[T]
): Aux[Option[H] *: T, H *: ev.Out] =
new Options[Option[H] *: T] {
type Out = H *: ev.Out
def apply(t: Option[H] *: T) =
(t.head.flatMap(h => ev(t.tail).map(t => h *: t)))
}
}
extension [T <: Tuple](t: T)(using ev: Options[T]) {
def sequence: Option[ev.Out] = ev(t)
}
// If we annotate this with an incorrect type it fails to typecheck and gives the inferred
// type as Option[?1.Out] rather than the expected fully-expanded type.
val x: Option[(Int, String, Boolean, Double)] =
(Option(1), Option("x"), Option(true), Option.empty[Double]).sequence
}
Is there a better way to do this?
Maybe the pretty-printer could try harder to get rid of these path-dependent things (bug report welcome), but if we avoid the Aux pattern and just use type parameters the problem goes away too:
object Blah {
trait Options[T <: Tuple, Out] {
def apply(t: T): Option[Out]
}
// one can always define `type Foo[T <: Tuple] = Options[T, _]`
// to hide the parameter.
object Options {
implicit def single[H]: Options[Option[H] *: EmptyTuple, H *: EmptyTuple] =
new Options[Option[H] *: EmptyTuple, H *: EmptyTuple] {
def apply(t: Option[H] *: EmptyTuple): Option[H *: EmptyTuple] =
t.head.map(_ *: EmptyTuple)
}
implicit def multiple[H, T <: Tuple, Tail <: Tuple](
implicit ev: Options[T, Tail]
): Options[Option[H] *: T, H *: Tail] =
new Options[Option[H] *: T, H *: Tail] {
def apply(t: Option[H] *: T) =
(t.head.flatMap(h => ev(t.tail).map(t => h *: t)))
}
}
extension [T <: Tuple, Out](t: T)(using ev: Options[T, Out]) {
def sequence: Option[Out] = ev(t)
}
// OK:
val x: Option[(Int, String, Boolean, Double)] =
(Option(1), Option("x"), Option(true), Option.empty[Double]).sequence
// error: Found: Option[Int *: String *: Boolean *: Double *: EmptyTuple]
// Required: String
val y: String =
(Option(1), Option("x"), Option(true), Option.empty[Double]).sequence
}
This is a pretty interesting gotcha I just stumbled upon: https://scastie.scala-lang.org/8r2pKMoXRyCk1wjUYeccHQ
Inlined:
def isTrue(b: Boolean): Boolean = b
val notTrue = !isTrue(_) // Missing parameter type\n\nI could not infer the type of the parameter _$1
I believe that is !((b: Boolean) => b)
, and since Function1
has no !
method, it gets lost. The error message is deceiving. I expect you intended it to expand like this:
val notTrue = (b: Boolean) => !isTrue(b)
Which compiles fine.
Actually, the error message suggests the expansion is as intended, but then the type inference still fails:
error: missing parameter type for expanded function ((<x$1: error>) => isTrue(x$1).unary_$bang)
Equivalent case without prefix operator:
> def m(i: Int): Int = i
def m(i: Int): Int
> val isFinite = m(_).isFinite
^
error: missing parameter type for expanded function ((<x$1: error>) => m(x$1).isFinite)
Probably moot since we will get Enums in Dotty, but thgis is one that frequently pops up for me and I find it annoying:
trait Error
case class SomethingBadHappened(msg: String) extends Error
case object UnexpectedError extends Error
//plus a few more
def someIO: IO[String, Thing]
def newIO: IO[Error, Thing] = someIO.leftMap(SomethingBadHappened(_)) //expected Error but got SomethingBadHappened
def newIO: IO[Error, Thing] = someIO.leftMap(SomethingBadHappened(_):Error) //compiles fine
also may be missing something with some language design principle, but this seems like a failure of the compiler to me
Uncommenting line 6 works, but would be nice if compiler could infer these instead of Nothing?
I wish I could write compose
as
def compose[G[_]: Functor]: Functor[F[G[_]]] =
Functor.make[F[G[_]]](
[A, B] => f => fga => map(fga)(Functor[G].map(_)(f))
)
That’s not type inference specific though, just syntax. Same for value level functions. This won’t work as well.
def compose[A, B, C](f: A => B, g: B => C): A => C = f(g(_))