返回类型为typeclass但没有其他类型信息

时间:2018-06-12 05:43:43

标签: scala functional-programming typeclass scala-cats

假设我有一些类型类:

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世界有什么能解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

只要您的方法确实需要根据某些条件返回3或1.0,并且该部分无法更改,那么您肯定需要返回类型的和类型。

这可以通过一个共同的超类来建模,这是你采取的方法,或者通过Eitherscalaz.\/等不相交的联合来建模,在这种情况下,你可以返回例如Int \/ Double。如果有许多潜在的类型可能会出现,那么你需要一个“或者任何一个”或者(更方便)shapeless HList,或者只是坚持超类Greetable

我认为这种情况的愚蠢不是来自解决方案,而是来自问题本身。基于某些内部逻辑返回两个或多个不同类型的方法实际上不是FP本身,是吗? :)