繁体   English   中英

scala 2.10中的Option.fold

[英]Option.fold in scala 2.10

在随后的scala 2.10.0-M7会话中:

scala> trait A
defined trait A
scala> class B extends A
defined class B
scala> class C extends A
defined class C
scala> Some(0).fold(new B){_=>new C}
<console>:11: error: type mismatch;
 found   : C
 required: B
              Some(0).fold(new B){_=>new C}

我希望编译器找到常见的超类型(即A)而不是抱怨。 是一般的类型推理限制,还是Option.fold定义方式的结果?

谢谢。

Scalas类型推理算法与Option.fold定义方式相结合的问题结果。

Scalas类型推断从左到右工作,这意味着它从最左边的符号开始,以搜索表达式的可能类型。 此外,对于方法参数列表,这意味着泛型类型绑定到最左边的参数列表填充的类型:

scala> def meth[A](a1: A, a2: A) = (a1, a2)
meth: [A](a1: A, a2: A)(A, A)

scala> meth(1, "")
res7: (Any, Any) = (1,"")

scala> def meth[A](a1: A)(a2: A) = (a1, a2)
meth: [A](a1: A)(a2: A)(A, A)

scala> meth(1)("")
<console>:10: error: type mismatch;
 found   : String("")
 required: Int
              meth(1)("")
                      ^

可以看出,在第一种情况下推断Any ,而在第二种情况下抛出编译器错误,因为A的类型由第一个参数列表绑定而第二个不能再改变它。

但是为了使问题中的方法调用起作用,在达到第二个参数列表之前,可能不会定义结果Option的类型。 因为这需要从右到左类型推断因此错误。 这与List.fold有些相同:

scala> List(1).foldLeft(Nil)((xs,x) => x::xs)
<console>:8: error: type mismatch;
 found   : List[Int]
 required: scala.collection.immutable.Nil.type
              List(1).foldLeft(Nil)((xs,x) => x::xs)
                                               ^

要使代码生效 ,必须明确指定生成的集合的类型,有关示例,请参阅@rks answer

请参阅此处的讨论以获得完整解释为什么定义它的定义。 简而言之: Option在许多方面都遵循集合的设计 - 因此当它的行为与集合的行为相同时更加清晰。

我觉得sschaef版本不够精确。 我不太了解scala(事实上,我从未使用它),但我认为这不取决于函数的实现方式。 我也没有理解“从左到右”的事情。

我没有最新版本的Scala,所以我无法测试你的示例venechka,但我认为可以通过添加一些类型注释来规避输入错误/限制。 例如,这里是sschaef的例子:

scala> List(1).foldLeft(Nil)((xs,x) => x::xs)
<console>:8: error: type mismatch;
 found   : List[Int]
 required: scala.collection.immutable.Nil.type
              List(1).foldLeft(Nil)((xs,x) => x::xs)
                                               ^

scala> List(1).foldLeft(Nil : List[Int])((xs,x) => x::xs)
res1: List[Int] = List(1)

而且我相信你可以通过以下方式做同样的事情:

Some(0).fold(new B : A){_=>new C}

再一次,我认为这是Scala typer的一个限制(可能是因为存在子类型),但在强烈肯定之前我必须环顾四周。

无论如何,在这里添加类型注释应该为你做的伎俩,所以尽情享受吧!

编辑:哦,sschaef编辑了他的答案,得到一些解释,可能会使我对这种行为的原因无效。 但它并没有改变类型注释将解决您的问题的事实。 所以我会让这条消息到位。

这是类型推断算法的一般限制。 跨列表的折叠具有相同的限制。 引用Scala编程

请注意,flatten的两个版本都需要在空列表中使用类型注释作为折叠的起始值。 这是由于Scala的类型推理器的限制,它无法自动推断列表的正确类型。

Scala的类型推断算法在具有多个参数列表的方法之间递增地工作。 第一个中指定的类型可用于第二个中的推理,第三个中的第二个等等。 如样式指南中所述 ,这允许您在fold函数中使用更简单的语法,因为推理引擎知道列表的类型和第一个参数列表中的累加器类型。

但是,由于它在连续的参数列表中递增地工作,因此在推断要fold的函数参数的类型之后,推理引擎将不会返回并更新返回类型(与累加器类型相同)。 相反,您会收到类型错误。

在上面的例子中,只需在累加器值上给出一个类型注释,你就会很好:

Some(0).fold(new B: A){_=>new C}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM