我正在编写一段看起来类似于以下内容的代码(Scastie for your convenience):
import scala.language.higherKinds
sealed trait Wrapping
sealed trait PinkWrap extends Wrapping
sealed trait GreenWrap extends Wrapping
sealed trait Foo[M[_], A] {}
case class MintFoo[M[_], A](a : A) extends Foo[M,A]
case class LiquoriceFoo[M[_], A](a : A) extends Foo[M,A]
sealed trait WrappedFoo[M[_], _, A]
case class FooInPinkWrap[M[_], A](m: Foo[M, A]) extends WrappedFoo[M, PinkWrap, A]
case class FooInGreenWrap[M[_], A](m: Foo[M, A]) extends WrappedFoo[M, GreenWrap, A]
object Utils {
def analyzeFoo[M[_], S <: Wrapping, A](w: WrappedFoo[M, S, A]): String = {
w match {
case FooInPinkWrap(f: Foo[M,A]) => tasteFoo[M,A](f)+" in Pink wrapping"
case FooInGreenWrap(f: Foo[M,A]) => tasteFoo[M,A](f)+" in Green wrapping"
}
}
def tasteFoo[M[_], A](f: Foo[M,A]) : String =
f match {
case MintFoo (a) => "Mint"
case LiquoriceFoo (a) => "Liquorice"
}
}
以前用Scala 2.11.7完全编译。
自从该项目受到Scala 2.12.4的影响(但事实上该问题已经在Scala 2.11.11中已经可以重现),它无法使用来自scalac
的以下消息进行编译{{1 }}:
case FooInPinkWrap(f: Foo[M,A]) => tasteFoo[M,A]
通过在&#34;构建设置&#34;中选择Scala版本2.12.4,可以在Scastie中重现这一点。
这令我感到困惑,因为M takes no type parameters, expected: one
确实是1-ary。
事实上,我遇到了与以下更简单的MWE(Scastie)相同的问题:
M
在后一段代码中用import scala.language.higherKinds
sealed trait GiftWrap
sealed trait PinkWrap extends GiftWrap
sealed trait GreenWrap extends GiftWrap
sealed trait Foo[M[_], A] {}
sealed trait WrappedFoo[M[_], S, A]
case class FooInPinkWrap[M[_], A](m: Foo[M, A]) extends WrappedFoo[M, PinkWrap, A]
case class FooInGreenWrap[M[_], A](m: Foo[M, A]) extends WrappedFoo[M, GreenWrap, A]
object Utils {
def tellColor[M[_], S <: GiftWrap, A](w: WrappedFoo[M, S, A]): String = {
w match {
case FooInPinkWrap(f: Foo[M,A]) => "Pink"
case FooInGreenWrap(f: Foo[M,A]) => "Green"
}
}
}
替换M
会导致
({type T[X] = M[X]})#T
注意pattern type is incompatible with expected type;
found : Playground.this.Foo[[X],A]
required: Playground.this.Foo[Any,Any]
Note: [X] <: Any, but trait Foo is invariant in type M.
You may wish to define M as +M instead. (SLS 4.5)
Note: A <: Any, but trait Foo is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
M does not take type parameters
。
为什么会这样?
我找不到2.11.11(次要版本)的更改日志特别有启发性。
更重要的是,如何编译旧代码
感谢。
答案 0 :(得分:3)
修改-通知强>
此帖子现在包含两部分:
产生相同错误的较短示例
那些并非完全&#34;最小&#34;例子,所以我试图进一步将它煮沸。 Foo
的整个层次结构和彩色包装的整个层次结构并不真正相关。这个小例子以基本相同的方式失败:
sealed trait Foo[M[_], P]
case class Bar[M[_]]() extends Foo[M, Int]
def f[M[_], S](x: Foo[M, S]): Int = x match {
case Bar() => g[M]
}
def g[M[_]] = 0
用2.12.4编译时,它给出:
error: M takes no type parameters, expected: one
case Bar() => g[M]
^
one error found
这里唯一有趣的是P
的类型参数Foo
,它被Int
中的具体Bar
取代,但又被制作成通用{{1}在S
的签名中。
在阅读relevant parts of documentation并查看similar, possibly related issues之后,我认为我可能不应该过多地推测为什么这在2.11中起作用,然后停止工作,现在没有&#39 ;工作在2.12。
相反,我将简单列出几种解决方法,希望您可以找到其中一种有用的方法。
1。您可以将构造函数转换为类型模式:
f
2. 您可以将构造函数值匹配转换为类型模式
变量(是的,Scala确实支持sealed trait Foo[M[_], P]
case class Bar[M[_]]() extends Foo[M, Int]
def f[M[_], S](x: Foo[M, S]): Int = x match {
case b: Bar[M] => g[M]
}
def g[M[_]] = 0
中的类型变量 - match
!),这是我很久没有注意到的引用[Odersky et人。 &#34;使用Scala编程&#34;,第一版,第275页]:
您也可以使用(小写)类型变量。
所以,你可以这样做,编译器实际上会尝试推断case
的一些事情:
m
}
3. 您可以将sealed trait Foo[M[_], P]
case class Bar[M[_]]() extends Foo[M, Int]
def f[M[_], S](x: Foo[M, S]): Int = x match {
case b: Bar[m] => g[m]
}
def g[M[_]] = 0
的RHS移动到case
的方法中:
Bar
4。(不是真正的解决方法,更多是观察)
如果您将类型参数sealed trait Foo[M[_], P]
case class Bar[M[_]]() extends Foo[M, Int] {
def g: Int = 0
}
def f[M[_], S](x: Foo[M, S]): Int = x match {
case b @ Bar() => b.g
}
修复为P
而不是将其保留为多态,则此方法有效:
Int
返回您的代码
以下是适用于您的代码的相同解决方法:
1。类型模式的构造函数模式:
sealed trait Foo[M[_], P]
case class Bar[M[_]]() extends Foo[M, Int]
def f[M[_]](x: Foo[M, Int]): Int = x match {
case Bar() => g[M]
}
def g[M[_]] = 0
2. :使用变量输入模式:
import scala.language.higherKinds
sealed trait Wrapping
sealed trait PinkWrap extends Wrapping
sealed trait GreenWrap extends Wrapping
sealed trait Foo[M[_], A] {}
case class MintFoo[M[_], A](a : A) extends Foo[M, A]
case class LiquoriceFoo[M[_], A](a : A) extends Foo[M, A]
sealed trait WrappedFoo[M[_], _, A]
case class FooInPinkWrap[M[_], A](m: Foo[M, A]) extends WrappedFoo[M, PinkWrap, A]
case class FooInGreenWrap[M[_], A](m: Foo[M, A]) extends WrappedFoo[M, GreenWrap, A]
object Utils {
def analyzeFoo[M[_], S <: Wrapping, A](w: WrappedFoo[M, S, A]): String = {
w match {
case f: FooInPinkWrap[M, A] => tasteFoo[M, A](f.m) + " in Pink wrapping"
case f: FooInGreenWrap[M, A] => tasteFoo[M, A](f.m) + " in Green wrapping"
}
}
def tasteFoo[M[_], A](f: Foo[M,A]) : String = {
f match {
case MintFoo(a) => "Mint"
case LiquoriceFoo(a) => "Liquorice"
}
}
}
3 :将sealed trait Wrapping
sealed trait PinkWrap extends Wrapping
sealed trait GreenWrap extends Wrapping
sealed trait Foo[M[_], A] {}
case class MintFoo[M[_], A](a : A) extends Foo[M, A]
case class LiquoriceFoo[M[_], A](a : A) extends Foo[M, A]
sealed trait WrappedFoo[M[_], _, A]
case class FooInPinkWrap[M[_], A](m: Foo[M, A]) extends WrappedFoo[M, PinkWrap, A]
case class FooInGreenWrap[M[_], A](m: Foo[M, A]) extends WrappedFoo[M, GreenWrap, A]
object Utils {
def analyzeFoo[M[_], S <: Wrapping, A](w: WrappedFoo[M, S, A]): String = {
w match {
case f: FooInPinkWrap[m, a] => tasteFoo[m, a](f.m) + " in Pink wrapping"
case f: FooInGreenWrap[m, a] => tasteFoo[m, a](f.m) + " in Green wrapping"
}
}
def tasteFoo[M[_], A](f: Foo[M,A]) : String = {
f match {
case MintFoo(a) => "Mint"
case LiquoriceFoo(a) => "Liquorice"
}
}
}
移至tasteBlah
:
WrappedFoo
4 (仅限最小化示例,不适用)。
(纯粹我的个人意见):我没有发现这种行为非常直观,也许你可以尝试将其作为一个问题提交。即使有人能找到一个很好的理由,为什么它毕竟不应该编译,但错误信息仍然非常混乱。