[英]How can I improve Scala's type inference with type parameters that don't show up in the first parameter list?
To illustrate my point, here an example: 为了说明我的观点,这里有一个例子:
abstract class Wrapper[A](wrapped: A) {
protected def someCondition: Boolean
def fold[B](whenTrue: => B)(whenFalse: => B): B =
if (someCondition) whenTrue else whenFalse
}
I'm trying to add a fold
method based on an arbitrary condition defined on a wrapped type A
. 我正在尝试添加基于在包装类型
A
上定义的任意条件的fold
方法。 The problem with the code above is that this wouldn't compile, although it could conceivably return Any
: 上面的代码的问题是,这不会编译,虽然它可以想象返回
Any
:
wrapper.fold("hi")(42)
because by the time the compiler reaches the second parameter list, B
has already been inferred to be String
. 因为在编译器到达第二个参数列表时,
B
已被推断为String
。 Suppose we don't want to have to write the type annotation. 假设我们不想编写类型注释。 We can try changing
fold
to this: 我们可以尝试将
fold
更改为:
def fold[B, B0 >: B](whenTrue: => B)(whenFalse: => B0): B0
but this also doesn't work, since B0
has already been resolved as String
at the end of the first parameter list, although it doesn't appear in it at all! 但是这也行不通,因为
B0
已经在第一个参数列表的末尾被解析为String
,尽管它根本没有出现在它中! The simple solution, of course, is to have a single parameter list, but f the sake of the example, let's say I want to keep the two parameter lists and try to make it work… Ideally, we should be able to delay the resolution of B0
. 当然,简单的解决方案是使用单个参数列表,但是为了示例,假设我想保留两个参数列表并尝试使其工作...理想情况下,我们应该能够延迟分辨率
B0
。 It would be great if we could write something like this: 如果我们能写出这样的东西会很棒:
def fold[B](whenTrue: => B)[B0 >: B](whenFalse: => B0): B0
But unfortunately this doesn't work. 但不幸的是,这不起作用。 Are there any workarounds?
有没有解决方法?
(I'm providing a first answer, but I'm of course looking for other workarounds as well.) (我提供了第一个答案,但我当然也在寻找其他解决方法。)
It seems that you want to mimic, thanks to compilation, the behavior and the goal of the Either
class. 由于编译,您似乎想要模仿
Either
类的行为和目标。 What you can do is the following: your fold will return an Either
object and get your B0 value from it: 你可以做的是:你的折叠将返回一个
Either
对象并从中获取你的B0值:
abstract class Wrapper[A](wrapped: A) {
protected def someCondition: Boolean
def fold[A, B](whenTrue: => B)(whenFalse: => A): Either[A, B] =
Either.cond(someCondition, whenTrue, whenFalse)
}
And let the implicit conversion either2mergeable
of the Either
class do the work: 让
Either
类的either2mergeable
的隐式转换完成工作:
scala> new Wrapper[Unit] {def someCondition = true}
res0: Wrapper[Unit] = $anon$1@77026e40
scala> res0.fold(42)("hi").merge
res1: Any = 42
Pro: 优点:
Either
structure allow you to directly retrieve A and B types Either
结构允许您直接检索A和B类型 Con: 缺点:
One solution is to create a temporary instance of a class that defines an apply
method simulating the second parameter list, which has itself the B0
type parameter: 一种解决方案是创建一个类的临时实例,该实例定义模拟第二个参数列表的
apply
方法,该方法本身具有B0
类型参数:
abstract class Wrapper[A](wrapped: A) {
// ... as before...
def fold[B](whenTrue: => B) = new FoldRequest[B](whenTrue)
class FoldRequest[B](whenTrue: => B) {
def apply[B0 >: B](whenFalse: => B0) =
if (someCondition) whenTrue else whenFalse
}
}
Then everything works correctly. 一切正常。 Could we even imagine that
def fold[B](whenTrue: => B)[B0 >: B](whenFalse: => B0): B0
could be interpreted as syntactic sugar for this?… 我们甚至可以想象
def fold[B](whenTrue: => B)[B0 >: B](whenFalse: => B0): B0
可以解释为这个语法糖?...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.