从Scala API中消除身份包装器类型

Ste*_*man 5 scala

假设我试图“抽象执行”:

import scala.language.higherKinds

class Operator[W[_]]( f : Int => W[Int] ) {
  def operate( i : Int ) : W[Int] = f(i)
}
Run Code Online (Sandbox Code Playgroud)

现在,我可以定义一个Operator[Future]或Operator[Task]等。例如...

import scala.concurrent.{ExecutionContext,Future}
def futureSquared( i : Int ) = Future( i * i )( ExecutionContext.global )
Run Code Online (Sandbox Code Playgroud)

以REPL风格...

scala> val fop = new Operator( futureSquared )
fop: Operator[scala.concurrent.Future] = Operator@105c54cb

scala> fop.operate(4)
res0: scala.concurrent.Future[Int] = Future(<not completed>)

scala> res0
res1: scala.concurrent.Future[Int] = Future(Success(16))
Run Code Online (Sandbox Code Playgroud)

万岁!

但是我也可能想要一个简单的同步版本,所以我在某个地方定义

type Identity[T] = T
Run Code Online (Sandbox Code Playgroud)

我可以定义一个同步运算符...

scala> def square( i : Int ) : Identity[Int] = i * i
square: (i: Int)Identity[Int]

scala> val sop = new Operator( square )
sop: Operator[Identity] = Operator@18f2960b

scala> sop.operate(9)
res2: Identity[Int] = 81
Run Code Online (Sandbox Code Playgroud)

甜。

但是,结果的推断类型是Identity[Int],而不是更简单,直接,这很尴尬Int。当然,这两种类型实际上是相同的,因此在各个方面都相同。但是我希望我的图书馆的客户对这些抽象过度执行的东西一无所知,不要混淆。

我可以手工写一个包装纸...

class SimpleOperator( inner : Operator[Identity] ) extends Operator[Identity]( inner.operate ) {
  override def operate( i : Int ) : Int = super.operate(i)
}
Run Code Online (Sandbox Code Playgroud)

确实有效...

scala> val simple = new SimpleOperator( sop )
simple: SimpleOperator = SimpleOperator@345c744e

scala> simple.operate(7)
res3: Int = 49
Run Code Online (Sandbox Code Playgroud)

但这感觉非常笨拙,特别是如果我的抽象执行类具有许多方法而不仅仅是一个方法。而且我必须记住,随着通用类的发展,使包装器保持同步。

是否有一些更通用,可维护的方法来获取版本,Operator[Identity]从而使包含类型从类型推断和API文档中消失?

Val*_*Dia 3

这更多的是长评论而不是答案......

但是,尴尬的是结果的推断类型是 Identity[Int],而不是更简单、直接的 Int。当然,这两种类型的表观类型实际上是相同的,因此在各方面都是相同的。但我希望我的图书馆的客户不要对这种抽象执行的东西一无所知。

这听起来像是您想转换Indentity[T]回T...您考虑过类型归属吗?

scala>def f[T](t: T): Identity[T] = t

scala>f(3)
// res11: Identity[Int] = 3

scala>f(3): Int
// res12: Int = 3

// So in your case
scala>sop.operate(9): Int
// res18: Int = 81
Run Code Online (Sandbox Code Playgroud)