键入类模式替代方法,以使用Scala中的方法丰富ADT

时间:2017-06-29 18:11:47

标签: scala functional-programming typeclass algebraic-data-types

我写了一个基本的代数数据类型,定义如下

sealed trait Fruit {def name: String}
case class Apple(name: String) extends Fruit
case class Orange(name: String, color: String) extends Fruit

我喜欢做的是定义Apple和Orange的通用方法。所以我决定通过Type Class模式提供这个功能。

sealed trait ServingFruit[T] {
    def peel(fruit: T): String
}

object FruitManager {
    def retrievePeelColor[T: ServingFruit](fruit: T): String =
        implicitly[ServingFruit[T]].peel(fruit)

    implicit object ApplePeelColor extends ServingFruit[Apple] {
        def peel(fruit: Apple): String = "GREEN"
    }

    implicit object OrangePeelColor extends ServingFruit[Orange] {
        def peel(fruit: Orange): String = fruit.color
    }
}

对于必要的(和不幸的)约束,我必须处理水果,作为共享基础特征的有界实例 Fruit

def myCodeMethod[F <: Fruit](fruit: F, out: String) = {
    import FruitManager._
    FruitManager.retrievePeelColor(fruit)
}

它带来了以下(以某种方式预期)异常。

could not find implicit value for evidence parameter of type my.path.to.fruit.ServingFruit[F] [error]FruitManager.retrievePeelColor(fruit)

然后,AFAIU herehere类型类模式是独立的类型,也许后者不适合我的场景。

重点是我正在努力找出一个有价值的解决方案,将我的ADT与基本特征的常用方法结合起来 - 同时 - 我想避免在ADT中提供方法(我试图保持FP导向)并使用这样的变通方法向我的Type类添加一个额外的Fruit转换器。

非常感谢任何帮助,谢谢。

安德烈

1 个答案:

答案 0 :(得分:2)

您需要将类型类见证传递给retrievePeelColor作为隐式参数:

scala> def retrievePeelColor[T](fruity: T)(implicit peeler: ServingFruit[T]) = peeler.peel(fruity)
retrievePeelColor: [T](fruity: T)(implicit peeler: ServingFruit[T])String

scala> retrievePeelColor(Apple("granny smith"))
res0: String = GREEN

scala> retrievePeelColor(Orange("bloody", "RED"))
res1: String = RED

至于设计:我不是一个经验丰富的设计人员,但我不会说在sealed trait中有一些方法不是&#34; FP风格& #34 ;.如果只有水果是可剥离的,并且数量有限,那么peel,恕我直言就可以有一个地方(由此我在谈论Fruit匹配的方法this,或Fruit随播广告对象中的静态成员。