从左到右自变量类型推断

从左到右自变量类型推断

问题描述:

我有一种情况,我希望根据(几个,比如5到10)optionals的存在对对象进行修改。所以基本上,如果我是势在必行做到这一点,是我的目标是为:从左到右自变量类型推断

var myObject = ... 
if (option.isDefined) { 
    myObject = myObject.modify(option.get) 
} 
if (option2.isDefined) { 
    myObject = myObject.someOtherModification(option2.get) 
} 

(请注意:也许我的对象是可变的,也许不是,这不是点这里。)

我想那会更好看,如果我试图执行写这个的流畅的方式,如(伪代码...):

myObject.optionally(option, _.modify(_)) 
     .optionally(option2, _.someOtherModification(_)) 

于是我开始了示例代码,其中的IntelliJ并不突出作为错误,但实际上并不构建。现在

class MyObject(content: String) { 
    /** Apply a transformation if the optional is present */ 
    def optionally[A](optional: Option[A], operation: (A, MyObject) => MyObject): MyObject = 
     optional.map(operation(_, this)).getOrElse(this) 
    /** Some possible transformation */ 
    def resized(length : Int): MyObject = new MyObject(content.substring(0, length)) 
} 
object Test { 
    val my = new MyObject("test") 
    val option = Option(2) 

    my.optionally(option, (size, value) => value.resized(size)) 
} 

,在我的情况下,MyObject类型是一些外部API的,所以我创建了一个隐式转换帮助,所以它确实是这样的:

// Out of my control 
class MyObject(content: String) { 
    def resized(length : Int): MyObject = new MyObject(content.substring(0, length)) 
} 

// What I did : create a rich type over MyObject 
class MyRichObject(myObject: MyObject) { 
    def optionally[A](optional: Option[A], operation: (A, MyObject) => MyObject): MyObject = optional.map(operation(_, myObject)).getOrElse(myObject) 
} 
// And an implicit conversion 
object MyRichObject { 
    implicit def apply(myObject: MyObject): MyRichObject = new MyRichObject(myObject) 
} 

而且那么,我这样使用它:

object Test { 
    val my = new MyObject("test") 
    val option = Option(2) 
    import MyRichObject._ 
    my.optionally(option, (size, value) => value.resized(size)) 
} 

而这一次,它在IntelliJ和编译时失败,因为0的类型不明: Error:(8, 26) missing parameter type my.optionally(option, (size, value) => value.resized(size))

为了使它的工作,我可以:

  1. 积极指定类型的size说法:my.optionally(option, (size: Int, value) => value.resized(size))
  2. 重写optionally到令行禁止版本

他们都不是很差,但如果我可能会问:

  • 是否有一个咖喱版本工作的原因,但一个多参数版本似乎无法推断参数化类型,
  • 难道是写在没有指定实际类型
  • ,并作为工作的方式奖金(虽然这可能是基于意见),你会怎么写它(某种foldLeft在我的脑海中出现一系列可选项......)?

一个选项:

// Out of my control 
class MyObject(content: String) { 
    def resized(length : Int): MyObject = new MyObject(content.substring(0, length)) 
} 

object MyObjectImplicits { 

    implicit class OptionalUpdate[A](val optional: Option[A]) extends AnyVal { 
    def update(operation: (A, MyObject) => MyObject): MyObject => MyObject = 
     (obj: MyObject) => optional.map(a => operation(a, obj)).getOrElse(obj) 
    } 

} 
object Test { 
    val my = new MyObject("test") 
    val option = Option(2) 
    import MyObjectImplicits._ 
    Seq(
    option.update((size, value) => value.resized(size)), 
    // more options... 
).foldLeft(my)(_) 
} 

还不如只用你的optionally的咖喱版本,就像你说的。

+0

我喜欢将可选类型的含义颠倒过来的想法,而不是MyObject(泛化:使参数化类型可转换,因此消除了另一端的任何参数化方法)。我同意你的结论:咖喱版至少看起来很好。让我觉得可能有些事情可以用证人类型来尝试(https://*.com/questions/8524878/implicit-conversion-vs-type-class?rq=1) – GPI

+0

另请参阅http://pchiusano.blogspot。 hk/2011/05/making-most-of-scalas-extremely-limited.html关于你观察到的类型推断的限制 – PH88

+0

感谢您的挖掘。我没有得到的是,在第一个示例实现(不含implicits)中,这实际上可行... – GPI

想想需要添加A型更好的方式有写这样说:

object Test { 
    val my = new MyObject("test") 
    val option = Some(2) 
    my.optionally[Int](option, (size, value) => value.resized(size)) 
} 

另一种方式,如果你只是将管理一个类型,因为对象的创建,是将一般的类创作,但要小心,使用此选项,你只能有每个实例一个类型:

class MyObject[A](content: String) { 
    def optionally(optional: Option[A], operation: (A, MyObject[A]) => MyObject[A]): MyObject[A] = 
    optional.map(operation(_, this)).getOrElse(this) 
    def resized(length : Int): MyObject[A] = new MyObject[A](content.substring(0, length)) 
} 

object Test { 
    val my = new MyObject[Int]("test") 
    val option = Some(2) 
    my.optionally(option, (size, value) => value.resized(size)) 
} 

正如你所看到的,现在都在仿制药是地方是德EN由int类型,因为那是你最想要的是什么,这里是一个漂亮的答案告诉了原因:

(只是一部分,我想在这里也适用:)

4)当推断的返回类型比您想要的更普遍,例如Any。

来源:In Scala, why does a type annotation must follow for the function parameters ? Why does the compiler not infer the function parameter types?为您考虑

+0

感谢您的第一个建议。回想起来似乎很明显,而且更好。你的第二个命题也很好,但有限制,另外我实际上不能修改MyObject。你的答案的其余部分似乎并不适用,因为它不能解释为什么当暗示进场时推理停止工作...... – GPI

+0

@GPI在这种情况下适用规则4):4)当推断的返回类型更一般时比你想要的,比如Any。 我的意思是你在哪里返回一般类型,当你想要一个特定的类型时,你不同意吗? –

+0

@GPI无论如何,我删除了无关的部分来澄清答案,我一直都很乐意提供帮助。 –