如何在案例类的每个字段上应用函数

时间:2015-12-12 12:29:42

标签: scala scalaz

让我们考虑一个分类问题:

object Classify extends App {
  type Tag = String
  type Classifier[A] = A => Set[Tag]

  case class Model(a: Int, b: String, c: String, d: String)

  def aClassifier : Classifier[Int] = _ => Set("A", "a")
  def bClassifier : Classifier[String] = _ => Set("B")
  def cClassifier : Classifier[String] = _ => Set("C")

  def modelClassifier : Classifier[Model] = {
    m => aClassifier(m.a) ++ bClassifier(m.b) ++ cClassifier(m.c)
  }

  println(modelClassifier(Model(1,"b", "c", "d")))
}

使用scalaz实现modelClassifier是否有更聪明的方法?

3 个答案:

答案 0 :(得分:1)

scalaz库没有按设计进行任何宏case class内省,但shapeless

考虑这样的定义:

import shapeless._
import shapeless.tag._
import shapeless.labelled._

trait Omit
val omit = tag[Omit]

case class Model(a: Int, b: String, c: String, d: String @@ Omit)

定义以下polymorphic function

object classifiers extends Poly1 {
  implicit def stringClassifier[K <: Symbol](implicit witness: Witness.Aux[K]) =
    at[FieldType[K, String]](value => Set(witness.value.name.toUpperCase))

  implicit def intClassifier[K <: Symbol](implicit witness: Witness.Aux[K]) =
    at[FieldType[K, Int]](value => {
      val name = witness.value.name
      Set(name.toUpperCase, name.toLowerCase)
    })

  implicit def omitClassifier[K, T] =
    at[FieldType[K, T @@ Omit]](_ => Set.empty[String])
}

现在您的modelClassifier可以完成:

def modelClassifier: Classifier[Model] = 
  m => LabelledGeneric[Model].to(m).map(classifiers).toList.reduce(_ union _)

你可以通过

查看
println(modelClassifier(Model(1, "b", "c", omit("d"))))

请注意,Type @@ TagType的子类型,因此model.d仍可用作String无处不在

答案 1 :(得分:0)

作为一个想法,请考虑以下代码:

 for (i <- 0 until model.productArity) yield {
  val fieldValue = model.productElement(i)
  fieldValue match {
    case x: Int => //use integer classifier
    case s: String => //use string classifier
    case _ => 
  }
 }

答案 2 :(得分:0)

您打算如何区分bClassifiercClassifier?按名字?按照声明的顺序?这听起来不是很聪明&#34;或者可靠。请考虑明确编码您的意图。这样的事情,也许是:

case class Classifiable[T](data: T, classifier: Classifier[T])
object Classifiable {
     def Null[T](data: T) = Classifiable(data, _ => Nil)
} 

case class Model(a: Classifiable[Int], b: Classifiable[String], c: Classifiable[String], d: Classifiable[String])

object Model {
   def apply(a: Int, b: String, c: String, d: String) = 
      Model(
         Classifiable(a, aClassifier), 
         Classifiable(b, bClassifier),
         Classifiable(c, cClassifier),
         Classifiable.Null(d)
      )
}

def modelClassifier(m: Model) = m
 .productIterator
 .collect { case x: Classifiable[_] => 
    x.classifier()(x)
 }
 .reduce(_ ++ _)     


 println(modelClassifier(Model(1,"b", "c", "d")))