Scala 重载一组类型的函数
假设我想用以下方式为函数类型定义算术运算符,如Scala 重载一组类型的函数,scala,implicit-conversion,typeclass,Scala,Implicit Conversion,Typeclass,假设我想用以下方式为函数类型定义算术运算符,如()=>Int,()=>Double等 def + (a : () => Int, b : () => Int) = new (() => Int) { def apply() = a() + b() } 在为所有可能的参数类型组合定义类似函数时,是否有任何方法可以避免锅炉板代码? 这些类型可以是内置的(Int,Long,Double),用户定义的类型(如货币,数量等),以
()=>Int
,()=>Double
等
def + (a : () => Int, b : () => Int) =
new (() => Int) {
def apply() = a() + b()
}
在为所有可能的参数类型组合定义类似函数时,是否有任何方法可以避免锅炉板代码?
这些类型可以是内置的(Int
,Long
,Double
),用户定义的类型(如货币
,数量
等),以及选项[T]
,其中T
可以是前面提到的任何类型
def + (a : () => Option[Int], b : () => Double) =
new (() => Option[Double])
{
// this specific code could be factored out
def apply() =
a() map { _ + b() }
}
您可以创建trait实例来定义特定类型操作的具体实现。然后要求将此特性作为操作的隐式参数,并调用这些具体实现
例如,检查源。您可以创建实例来定义特定类型操作的具体实现。然后要求将此特性作为操作的隐式参数,并调用这些具体实现
例如,检查源。在我看来,通过引入
trait PlusDefined[A,B] {
type Ret
def plus(a : A, b : B) : Ret
}
以及为不同类型引入隐式值。我当前的解决方案无法避免所有锅炉板代码(如选项[t]的显式重载),但看起来可行:
import language.implicitConversions
trait Conversion[From, To]
{
def convert(from : From) : To
}
object Conversions {
implicit def toOption[T, U](implicit ev : Conversion[T,U])
: Conversion[T, Option[U]] =
new Conversion[T, Option[U]]
{
def convert(x : T) = Some(ev.convert(x))
}
implicit def toOptionId[T]
: Conversion[T, Option[T]] =
new Conversion[T, Option[T]]
{
def convert(x : T) = Some(x)
}
implicit def betweenOptions[T, U](implicit ev : Conversion[T,U])
: Conversion[Option[T], Option[U]] =
new Conversion[Option[T], Option[U]]
{
def convert(x : Option[T]) = x map { y => ev.convert(y) }
}
implicit val int2double =
new Conversion[Int, Double]{ def convert(x : Int) = x }
implicit val int2long =
new Conversion[Int, Long] { def convert(x : Int) = x }
implicit val long2double =
new Conversion[Long, Double]{ def convert(x : Long) = x }
}
trait PlusDefined[A,B]
{
type Ret
def plus(a : A, b : B) : Ret
}
trait Addable_Level1 {
implicit def rightConversion[A,B](implicit c : Conversion[A,B],
ev : PlusDefined[B,B])
: PlusDefined[A,B] =
new PlusDefined[A,B]
{
type Ret = PlusDefined[B,B]#Ret
def plus(a : A, b : B) = ev.plus(c.convert(a), b)
}
implicit def leftConversion[A,B](implicit c : Conversion[B,A],
ev : PlusDefined[A,A])
: PlusDefined[A,B] =
new PlusDefined[A,B]
{
type Ret = PlusDefined[A,A]#Ret
def plus(a : A, b : B) = ev.plus(a, c.convert(b))
}
}
trait Addable_Level2 extends Addable_Level1
{
implicit def rightOpt[A,B](implicit ev : PlusDefined[A,B])
: PlusDefined[A,Option[B]] =
new PlusDefined[A,Option[B]]
{
type Ret = Option[PlusDefined[A,B]#Ret]
def plus(a : A, b : Option[B]) = b map { x => ev.plus(a,x) }
}
implicit def leftOpt[A,B](implicit ev : PlusDefined[A,B])
: PlusDefined[Option[A],B] =
new PlusDefined[Option[A],B]
{
type Ret = Option[PlusDefined[A,B]#Ret]
def plus(a : Option[A], b : B) = a map { x => ev.plus(x,b) }
}
implicit def bothOpt[A,B](implicit ev : PlusDefined[A,B])
: PlusDefined[Option[A],Option[B]] =
new PlusDefined[Option[A],Option[B]]
{
type Ret = Option[PlusDefined[A,B]#Ret]
def plus(a : Option[A], b : Option[B]) =
(a,b) match {
case (Some(x), Some(y)) => Some(ev.plus(x,y))
case _ => None
}
}
}
object Addable extends Addable_Level2 {
implicit def fromNumeric[T : Numeric]
: PlusDefined[T,T] = new PlusDefined[T,T]
{
type Ret = T
def plus(a : T, b : T) = implicitly[Numeric[T]].plus(a,b)
}
}
在我看来,这个问题可以通过引入
trait PlusDefined[A,B] {
type Ret
def plus(a : A, b : B) : Ret
}
以及为不同类型引入隐式值。我当前的解决方案无法避免所有锅炉板代码(如选项[t]的显式重载),但看起来可行:
import language.implicitConversions
trait Conversion[From, To]
{
def convert(from : From) : To
}
object Conversions {
implicit def toOption[T, U](implicit ev : Conversion[T,U])
: Conversion[T, Option[U]] =
new Conversion[T, Option[U]]
{
def convert(x : T) = Some(ev.convert(x))
}
implicit def toOptionId[T]
: Conversion[T, Option[T]] =
new Conversion[T, Option[T]]
{
def convert(x : T) = Some(x)
}
implicit def betweenOptions[T, U](implicit ev : Conversion[T,U])
: Conversion[Option[T], Option[U]] =
new Conversion[Option[T], Option[U]]
{
def convert(x : Option[T]) = x map { y => ev.convert(y) }
}
implicit val int2double =
new Conversion[Int, Double]{ def convert(x : Int) = x }
implicit val int2long =
new Conversion[Int, Long] { def convert(x : Int) = x }
implicit val long2double =
new Conversion[Long, Double]{ def convert(x : Long) = x }
}
trait PlusDefined[A,B]
{
type Ret
def plus(a : A, b : B) : Ret
}
trait Addable_Level1 {
implicit def rightConversion[A,B](implicit c : Conversion[A,B],
ev : PlusDefined[B,B])
: PlusDefined[A,B] =
new PlusDefined[A,B]
{
type Ret = PlusDefined[B,B]#Ret
def plus(a : A, b : B) = ev.plus(c.convert(a), b)
}
implicit def leftConversion[A,B](implicit c : Conversion[B,A],
ev : PlusDefined[A,A])
: PlusDefined[A,B] =
new PlusDefined[A,B]
{
type Ret = PlusDefined[A,A]#Ret
def plus(a : A, b : B) = ev.plus(a, c.convert(b))
}
}
trait Addable_Level2 extends Addable_Level1
{
implicit def rightOpt[A,B](implicit ev : PlusDefined[A,B])
: PlusDefined[A,Option[B]] =
new PlusDefined[A,Option[B]]
{
type Ret = Option[PlusDefined[A,B]#Ret]
def plus(a : A, b : Option[B]) = b map { x => ev.plus(a,x) }
}
implicit def leftOpt[A,B](implicit ev : PlusDefined[A,B])
: PlusDefined[Option[A],B] =
new PlusDefined[Option[A],B]
{
type Ret = Option[PlusDefined[A,B]#Ret]
def plus(a : Option[A], b : B) = a map { x => ev.plus(x,b) }
}
implicit def bothOpt[A,B](implicit ev : PlusDefined[A,B])
: PlusDefined[Option[A],Option[B]] =
new PlusDefined[Option[A],Option[B]]
{
type Ret = Option[PlusDefined[A,B]#Ret]
def plus(a : Option[A], b : Option[B]) =
(a,b) match {
case (Some(x), Some(y)) => Some(ev.plus(x,y))
case _ => None
}
}
}
object Addable extends Addable_Level2 {
implicit def fromNumeric[T : Numeric]
: PlusDefined[T,T] = new PlusDefined[T,T]
{
type Ret = T
def plus(a : T, b : T) = implicitly[Numeric[T]].plus(a,b)
}
}
您能提供更多您正在谈论的用户定义类的示例吗?您是否暗示对它们有一些限制(例如,带有一个参数的case类等)?否则我猜范围太广了。我也不知道你到底想做什么,但听起来你可能是在从scalaz中重新发明一些东西。首先,你可以去掉
new
样板:def+(a:()=>Int,b:()=>Int=>a()+b()
事实上,我不想对要支持的用户定义类型施加限制(但显然它们将是带有一个参数的case类)。我想在引入类型类的基础上找到一个解决方案,比如trait-hascovertion[From,to]{def-convert(x:From):to}
和trait-Addable[T]{def-plus(x:T,y:T):T}
,但我不知道如何让它们协同工作。你能提供更多你正在谈论的用户定义类的例子吗?您是否暗示对它们有一些限制(例如,带有一个参数的case类等)?否则我猜范围太广了。我也不知道你到底想做什么,但听起来你可能是在从scalaz中重新发明一些东西。首先,你可以去掉new
样板:def+(a:()=>Int,b:()=>Int=>a()+b()
事实上,我不想对要支持的用户定义类型施加限制(但显然它们将是带有一个参数的case类)。我想在引入类型类的基础上找到一个解决方案,比如trait hascovertion[From,to]{def convert(x:From):to}
和trait Addable[T]{def plus(x:T,y:T):T}
但我不知道如何让它们一起工作。谢谢,但我觉得scala.math.Numeric和Spire不能解决混合算术的问题谢谢,但我觉得scala.math.Numeric和Spire不能解决混合算术的问题