假设我有一些类型类:
trait Greeter[A] {
def greet(a: A): String
}
我想写一个方法来返回存在这个类型类的实例的值:
implicit val intGreeter = new Greeter[Int] {
def greet(n: Int): String = s"Hello, integer $n!"
}
implicit val doubleGreeter = new Greeter[Double] {
def greet(d: Double): String = s"Hello, double $d"
}
def foo(b: Boolean): <X> = {
if (b) 3 else 1.0
}
其中<X>
是某种类型的签名。然后使用它:
val g: <X> = foo(true)
println(implicitly[Greeter[<X>]].greet(g))
当然这并不能直接起作用。我可以这样做:
trait Greetable {
def greet: String
}
def getGreetable[A : Greeter](a: A) = new Greetable {
def greet: String = implicitly[Greeter[A]].greet(a)
}
def foo(b: Boolean): Greetable = {
if (b) getGreetable(3) else getGreetable(1.0)
}
这很好用,但看起来有点不方便,而且不是真正可扩展的。我必须为每个类型类定义一个相应的特征。如果我想要一个包含两个类型类的实例的返回类型,该怎么办?还是n?这也感觉像是一种非常简单的方法; FP世界有什么能解决这个问题吗?
答案 0 :(得分:1)
只要您的方法确实需要根据某些条件返回3或1.0,并且该部分无法更改,那么您肯定需要返回类型的和类型。
这可以通过一个共同的超类来建模,这是你采取的方法,或者通过Either
,scalaz.\/
等不相交的联合来建模,在这种情况下,你可以返回例如Int \/ Double
。如果有许多潜在的类型可能会出现,那么你需要一个“或者任何一个”或者(更方便)shapeless HList,或者只是坚持超类Greetable
。
我认为这种情况的愚蠢不是来自解决方案,而是来自问题本身。基于某些内部逻辑返回两个或多个不同类型的方法实际上不是FP本身,是吗? :)