Scala 从函数到自定义类型集的转换

Scala 从函数到自定义类型集的转换,scala,implicit-conversion,typeclass,Scala,Implicit Conversion,Typeclass,我有一组类似这样的类,它们(令人烦恼的)不在单一继承层次结构中: trait Mxy[A,B] { def apply(a: A): B } trait Mzz[ C ] { def apply(c: C): C } trait Mix[ B] { def apply(i: Int): B } trait Mxi[A ] { def apply(a: A): Int } trait Mii { def apply(i: Int): Int } 挑战在于使用转换器将Function

我有一组类似这样的类,它们(令人烦恼的)不在单一继承层次结构中:

trait Mxy[A,B] { def apply(a: A): B }
trait Mzz[ C ] { def apply(c: C): C }
trait Mix[  B] { def apply(i: Int): B }
trait Mxi[A  ] { def apply(a: A): Int }
trait Mii      { def apply(i: Int): Int }
挑战在于使用转换器将
Function1
映射到这些类中(因此您可以调用
.m
进行切换);直接隐式转换使得很难弄清楚代码到底在做什么

只要最具体的
M
总是可以的,它是可行的。您可以编写类似以下内容的隐式转换

abstract class MxyMaker[A, B] { def m: Mxy[A, B] }
abstract class MiiMaker       { def m: Mii       }

trait Priority2 {
  implicit def f2mxy[A, B](f: Function1[A, B]) = 
    new MxyMaker[A, B] { def m = new Mxy[A, B] { def apply(a: A) = f(a) } }
}
// Bunch of missing priorities here in the full case
object Convert extends Priority2 {
  implicit def f2mii[A](f: Function1[A, Int])(implicit evA: Int =:= A) = 
    new MiiMaker { def m = new Mii{ 
        def apply(i: Int) = (f.asInstanceOf[Function1[Int,Int]]).apply(i) 
    } }
}
现在,只要你有一个
Int=>Int
,你就会得到一个
Mii
,而对于其他任何东西,你都会得到一个
Mxy
。(如果不要求
evA
,则
((a:Any)=>5).m
作为
Mii
出现,因为函数1在其输入参数中的反差。)

到目前为止还不错。但如果您所处的环境不需要
Mii
,而需要
Mxy
,该怎么办

def muse[A, B](m: Mxy[A,B]) = ???
现在推断最具体的类型不是你想要的。但是,唉

scala> muse( ((i: Int) => 5).m )
  <console>:18: error: type mismatch;
   found   : Mii
   required: Mxy[?,?]
                muse( ((i: Int) => 5).m )
                                      ^
scala>muse((i:Int)=>5.m)
:18:错误:类型不匹配;
发现:信息产业部
必填项:Mxy[?,?]
缪斯(((i:Int)=>5.m)
^
现在怎么办?如果
Mxy
Mii
的一个超类,那就可以了,但它不是,我无法更改它。我可以用一个输出类型参数化
m
,并拥有一组类似typeclass的东西,根据输出类型进行正确的转换,然后要求用户手动键入
.m[Mxy]
。但是我想跳过手动部分,以某种方式从调用
muse
中提取类型上下文,而不会弄乱
val mippy=((I:Int)=5.m
之类的内容


机敏的人也许能在野外想到这样的情况,但使用这种“最小化”方法更容易获得正确的原则。

缪斯需要一个MxyMaker如何?:
def muse[a,B](m:MxyMaker[a,B])={m.m}
或者如果您不想更改
muse
则使用外部方法包装它:
def museOuter[A,B](m:MxyMaker[A,B])={muse(m.m)}
@AkosKrivachy-不幸的是,我无法更改
muse
,我关心的实际情况也不允许使用外部方法包装(因为像
muse
)这样的方法太多了。既然不能让
Mxy
成为超类
Mii
,为什么不简单地定义从
Mii
Mxy[Int,Int]的隐式转换呢
?@RégisJean-Gilles-因为一般来说,你不希望他们在不知情的情况下到处乱跳,因为Mii是未装箱的,而Mxy是装箱的,使用Mii的唯一原因通常是为了性能。否则,我会这么做——总体来说,这是个好主意。